@t275005746/gse 0.1.0 → 0.1.2
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 -42
- package/.github/ISSUE_TEMPLATE/change_request.yml +50 -50
- package/.github/ISSUE_TEMPLATE/config.yml +5 -5
- package/.github/PULL_REQUEST_TEMPLATE.md +38 -38
- package/.github/workflows/validate-gse.yml +33 -33
- package/.gse/README.md +18 -18
- package/.gse/gse-development-protocol.md +50 -50
- package/.gse/project-profile.md +29 -29
- package/.gse/quality-gates.md +25 -25
- package/.gse/releases/public-registry-publication-npm.md +49 -0
- package/.gse/releases/public-release-owner-required.md +65 -65
- package/.gse/releases/public-security-contact-owner-required.md +45 -45
- package/.gse/state.json +147 -27
- package/CHANGELOG.md +31 -15
- package/CONTRIBUTING.md +64 -64
- package/LICENSE +21 -21
- package/README.md +14 -7
- package/README.zh-CN.md +14 -7
- package/SECURITY.md +41 -41
- package/SKILL.md +32 -12
- package/SUPPORT.md +38 -38
- package/assets/marketplace/README.md +7 -7
- package/assets/marketplace/gse-listing.json +75 -75
- package/assets/templates/acceptance-execution-packet.md +73 -73
- package/assets/templates/adr.md +14 -14
- package/assets/templates/change-brief.md +16 -16
- package/assets/templates/design.md +18 -18
- package/assets/templates/dispatch-packet.md +100 -92
- package/assets/templates/evidence.md +15 -9
- package/assets/templates/execution-quality-pack.md +65 -65
- package/assets/templates/goal-map.md +21 -21
- package/assets/templates/host-adapter.md +48 -48
- package/assets/templates/host-ui-invocation-record.md +42 -42
- package/assets/templates/incident-review.md +60 -60
- package/assets/templates/public-channel-publication-record.md +49 -49
- package/assets/templates/public-ci-run-record.md +53 -53
- package/assets/templates/public-release-record.md +65 -65
- package/assets/templates/public-repository-settings-record.md +59 -59
- package/assets/templates/public-security-contact-record.md +45 -45
- package/assets/templates/release-trust-record.md +32 -32
- package/assets/templates/review.md +18 -18
- package/assets/templates/role-fallback-packet.md +49 -0
- package/assets/templates/spec.md +16 -16
- package/assets/templates/target-adoption-evidence.md +29 -29
- package/assets/templates/tasks.md +17 -17
- package/assets/templates/update-release-acceptance-record.md +58 -58
- package/examples/README.md +22 -22
- package/examples/agent-runtime-host/.claude/gse-adapter.md +6 -6
- package/examples/agent-runtime-host/.codex/gse-adapter.md +7 -7
- package/examples/agent-runtime-host/.gse/goal-map.md +7 -7
- package/examples/agent-runtime-host/.gse/project-profile.md +27 -27
- package/examples/agent-runtime-host/.gse/tooling.md +5 -5
- package/examples/agent-runtime-host/.mcp.json +9 -9
- package/examples/agent-runtime-host/AGENTS.md +5 -5
- package/examples/agent-runtime-host/README.md +10 -10
- package/examples/agent-runtime-host/docs/model-routing.md +5 -5
- package/examples/cli-tool/.gse/project-profile.md +21 -21
- package/examples/cli-tool/AGENTS.md +5 -5
- package/examples/cli-tool/README.md +12 -12
- package/examples/cli-tool/package.json +21 -21
- package/examples/small-app/.env.example +2 -2
- package/examples/small-app/.github/workflows/ci.yml +8 -8
- package/examples/small-app/AGENTS.md +5 -5
- package/examples/small-app/README.md +12 -12
- package/examples/small-app/package.json +26 -26
- package/examples/small-app/playwright.config.ts +4 -4
- package/package.json +52 -44
- package/references/adoption-recipes.md +171 -171
- package/references/agent-roles.md +42 -21
- package/references/architecture-health.md +101 -101
- package/references/benchmark-audit.md +73 -73
- package/references/commands.md +74 -45
- package/references/community-channels.md +46 -46
- package/references/compatibility.md +70 -70
- package/references/design-basis.md +38 -38
- package/references/domain-model.md +129 -129
- package/references/domain-quality-gates.md +75 -75
- package/references/drift-audit.md +81 -80
- package/references/evidence-taxonomy.md +145 -108
- package/references/file-ownership.md +97 -93
- package/references/final-form-roadmap.md +201 -0
- package/references/final-readiness.md +84 -84
- package/references/forward-test.md +133 -133
- package/references/goal-map.md +36 -36
- package/references/host-adapters.md +129 -101
- package/references/learning-system.md +42 -26
- package/references/maintenance-cadence.md +51 -0
- package/references/marketplace-discovery.md +46 -46
- package/references/model-routing.md +103 -103
- package/references/open-source-defaults.md +39 -39
- package/references/operating-model.md +52 -52
- package/references/packaging.md +277 -277
- package/references/project-agent-workspace.md +89 -89
- package/references/project-bootstrap.md +122 -122
- package/references/project-guards.md +52 -0
- package/references/project-profile.md +57 -57
- package/references/public-release.md +174 -174
- package/references/quality-gates.md +96 -89
- package/references/recovery.md +176 -176
- package/references/release-trust.md +43 -43
- package/references/release.md +126 -126
- package/references/review.md +141 -141
- package/references/role-dispatch-fallback.md +54 -0
- package/references/router.md +90 -90
- package/references/spec-workflow.md +66 -66
- package/references/task-levels.md +81 -81
- package/references/tool-adapters.md +80 -70
- package/scripts/audit-acceptance-execution-packet.mjs +133 -133
- package/scripts/audit-adoption-recipes.mjs +99 -99
- package/scripts/audit-change-lifecycle.mjs +77 -77
- package/scripts/audit-change-system.mjs +134 -134
- package/scripts/audit-ci-readiness.mjs +107 -107
- package/scripts/audit-close-gate-hardening.mjs +188 -0
- package/scripts/audit-close-gate.mjs +448 -262
- package/scripts/audit-command-adapters.mjs +91 -91
- package/scripts/audit-command-execution.mjs +212 -199
- package/scripts/audit-commands.mjs +7 -5
- package/scripts/audit-compatibility.mjs +149 -149
- package/scripts/audit-completion-plan-drill.mjs +230 -0
- package/scripts/audit-completion-readiness.mjs +290 -287
- package/scripts/audit-continue-preflight.mjs +234 -0
- package/scripts/audit-distribution.mjs +251 -251
- package/scripts/audit-domain-quality-gates.mjs +108 -108
- package/scripts/audit-evidence-levels.mjs +217 -0
- package/scripts/audit-evidence-placeholders.mjs +126 -126
- package/scripts/audit-evidence-review-queue.mjs +206 -0
- package/scripts/audit-final-acceptance-packet.mjs +9 -9
- package/scripts/audit-final-form-progress-report.mjs +19 -18
- package/scripts/audit-final-form-roadmap.mjs +157 -0
- package/scripts/audit-final-form-stale-copy.mjs +2 -2
- package/scripts/audit-final-readiness-promotion.mjs +255 -255
- package/scripts/audit-final-readiness.mjs +226 -226
- package/scripts/audit-fixtures.mjs +154 -154
- package/scripts/audit-fresh-session-readiness.mjs +177 -177
- package/scripts/audit-host-capabilities.mjs +237 -0
- package/scripts/audit-host-runtime-evidence-handoff.mjs +159 -159
- package/scripts/audit-host-runtime-invocation-drill.mjs +240 -240
- package/scripts/audit-host-runtime-invocations.mjs +254 -254
- package/scripts/audit-host-ui-invocation.mjs +132 -132
- package/scripts/audit-installed-sync.mjs +203 -0
- package/scripts/audit-learning-drift.mjs +292 -0
- package/scripts/audit-learning-promotion.mjs +351 -0
- package/scripts/audit-learning-system.mjs +24 -14
- package/scripts/audit-local-final-form-completion.mjs +11 -10
- package/scripts/audit-maintenance-cadence.mjs +139 -0
- package/scripts/audit-maintenance-snapshot.mjs +181 -0
- package/scripts/audit-marketplace-discovery.mjs +122 -122
- package/scripts/audit-npm-package-metadata.mjs +160 -154
- package/scripts/audit-npm-publish-dry-run.mjs +194 -166
- package/scripts/audit-npm-tarball-install.mjs +195 -189
- package/scripts/audit-open-source-defaults.mjs +92 -92
- package/scripts/audit-open-source-readiness.mjs +97 -97
- package/scripts/audit-owner-external-gate-kit.mjs +12 -11
- package/scripts/audit-project-guards.mjs +189 -0
- package/scripts/audit-project.mjs +144 -141
- package/scripts/audit-public-acceptance-command-dry-run-drill.mjs +203 -203
- package/scripts/audit-public-acceptance-handoff.mjs +10 -10
- package/scripts/audit-public-acceptance-readiness.mjs +222 -222
- package/scripts/audit-public-channel-publication.mjs +248 -248
- package/scripts/audit-public-ci-run.mjs +184 -184
- package/scripts/audit-public-collaboration-templates.mjs +98 -98
- package/scripts/audit-public-external-gate-probe.mjs +206 -206
- package/scripts/audit-public-release-checklist.mjs +17 -15
- package/scripts/audit-public-release-decision.mjs +201 -201
- package/scripts/audit-public-release-metadata.mjs +176 -176
- package/scripts/audit-public-repository-settings.mjs +237 -237
- package/scripts/audit-public-security-contact.mjs +171 -171
- package/scripts/audit-readme-docs.mjs +6 -4
- package/scripts/audit-recovery-readiness.mjs +98 -98
- package/scripts/audit-release-bundle.mjs +13 -11
- package/scripts/audit-release-owner-action-plan-drill.mjs +5 -4
- package/scripts/audit-release-owner-action-plan.mjs +10 -10
- package/scripts/audit-release-readiness.mjs +106 -106
- package/scripts/audit-release-status-manifest.mjs +4 -4
- package/scripts/audit-release-trust.mjs +62 -62
- package/scripts/audit-remote-distribution.mjs +266 -266
- package/scripts/audit-roadmap-consistency.mjs +234 -230
- package/scripts/audit-role-dispatch-fallback.mjs +212 -0
- package/scripts/audit-session-sync.mjs +127 -0
- package/scripts/audit-signing.mjs +147 -147
- package/scripts/audit-state-freshness.mjs +20 -14
- package/scripts/audit-state-repair.mjs +360 -0
- package/scripts/audit-target-adoption-evidence.mjs +117 -117
- package/scripts/audit-target-hardening-drills.mjs +267 -0
- package/scripts/audit-target-project.mjs +507 -507
- package/scripts/audit-tool-fallback-policy.mjs +180 -0
- package/scripts/audit-ui-browser-evidence-policy.mjs +191 -0
- package/scripts/audit-update-release-acceptance.mjs +136 -136
- package/scripts/audit-v1-target-validation.mjs +269 -269
- package/scripts/audit-validation-profiles.mjs +125 -123
- package/scripts/backfill-evidence-levels.mjs +98 -0
- package/scripts/check-encoding.mjs +72 -0
- package/scripts/close-change.mjs +116 -116
- package/scripts/discover-project-profile.mjs +307 -307
- package/scripts/generate-command-adapter.mjs +231 -231
- package/scripts/generate-continue-packet.mjs +1214 -0
- package/scripts/generate-final-acceptance-packet.mjs +188 -173
- package/scripts/generate-final-form-progress-report.mjs +191 -189
- package/scripts/generate-host-runtime-evidence-handoff.mjs +198 -191
- package/scripts/generate-maintenance-snapshot.mjs +216 -0
- package/scripts/generate-owner-external-gate-kit.mjs +295 -295
- package/scripts/generate-public-acceptance-handoff.mjs +168 -156
- package/scripts/generate-public-release-checklist.mjs +207 -207
- package/scripts/generate-release-bundle.mjs +505 -505
- package/scripts/generate-release-owner-action-plan.mjs +172 -171
- package/scripts/generate-release-status-manifest.mjs +199 -198
- package/scripts/generate-session-prompt.mjs +188 -188
- package/scripts/gse.mjs +67 -67
- package/scripts/init-change.mjs +265 -265
- package/scripts/init-project.mjs +793 -712
- package/scripts/install-gse.mjs +234 -234
- package/scripts/lib/evidence-placeholders.mjs +28 -28
- package/scripts/package-gse.mjs +174 -174
- package/scripts/probe-public-external-gates.mjs +167 -167
- package/scripts/record-host-invocation.mjs +151 -151
- package/scripts/record-learning.mjs +37 -8
- package/scripts/record-public-channel-publication.mjs +178 -178
- package/scripts/record-public-ci-run.mjs +180 -180
- package/scripts/record-public-release.mjs +175 -175
- package/scripts/record-public-repository-settings.mjs +209 -209
- package/scripts/record-public-security-contact.mjs +157 -157
- package/scripts/record-session-sync.mjs +87 -0
- package/scripts/run-gse-command.mjs +79 -47
- package/scripts/run-validation-profile.mjs +24 -5
- package/scripts/sign-gse-package.mjs +83 -83
- package/scripts/update-project-state.mjs +223 -223
- package/scripts/validate-gse.mjs +216 -0
- package/scripts/verify-gse-package.mjs +85 -85
|
@@ -1,132 +1,132 @@
|
|
|
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 recordPath = readArg('--record')
|
|
17
|
-
const jsonOnly = args.includes('--json')
|
|
18
|
-
|
|
19
|
-
function read(relativePathOrFullPath) {
|
|
20
|
-
const fullPath = path.isAbsolute(relativePathOrFullPath) ? relativePathOrFullPath : path.join(root, relativePathOrFullPath)
|
|
21
|
-
return fs.existsSync(fullPath) ? fs.readFileSync(fullPath, 'utf8').replace(/^\uFEFF/, '') : ''
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function exists(relativePath) {
|
|
25
|
-
return fs.existsSync(path.join(root, relativePath))
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function run(script, commandArgs) {
|
|
29
|
-
const result = spawnSync(process.execPath, [path.join(root, 'scripts', script), ...commandArgs], {
|
|
30
|
-
cwd: root,
|
|
31
|
-
encoding: 'utf8',
|
|
32
|
-
windowsHide: true,
|
|
33
|
-
})
|
|
34
|
-
return {
|
|
35
|
-
command: [process.execPath, path.join(root, 'scripts', script), ...commandArgs].join(' '),
|
|
36
|
-
status: result.status ?? 1,
|
|
37
|
-
stdout: (result.stdout ?? '').trim(),
|
|
38
|
-
stderr: (result.stderr ?? '').trim(),
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
function parseJson(text) {
|
|
43
|
-
try { return JSON.parse(text) } catch { return null }
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function check(id, label, ok, evidence, risk = '') {
|
|
47
|
-
return { id, label, status: ok ? 'passed' : 'failed', evidence, risk }
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
const target = fs.mkdtempSync(path.join(os.tmpdir(), 'gse-host-ui-'))
|
|
51
|
-
fs.mkdirSync(target, { recursive: true })
|
|
52
|
-
fs.writeFileSync(path.join(target, 'AGENTS.md'), '# Host UI Fixture\n', 'utf8')
|
|
53
|
-
const initRun = run('init-project.mjs', ['--target', target, '--mode', 'enterprise', '--json'])
|
|
54
|
-
const adapterRun = run('generate-command-adapter.mjs', ['--target', target, '--host', 'all', '--json'])
|
|
55
|
-
const commandRun = run('run-gse-command.mjs', ['--target', target, '--command', '/gse help', '--json'])
|
|
56
|
-
const adapterData = parseJson(adapterRun.stdout)
|
|
57
|
-
const commandData = parseJson(commandRun.stdout)
|
|
58
|
-
const claudeCommand = read(path.join(target, '.claude', 'commands', 'gse.md'))
|
|
59
|
-
const codexPointer = read(path.join(target, '.codex', 'gse-command.md'))
|
|
60
|
-
const record = recordPath ? read(path.resolve(recordPath)) : ''
|
|
61
|
-
const recordHasEvidence =
|
|
62
|
-
Boolean(record) &&
|
|
63
|
-
record.includes('## Host') &&
|
|
64
|
-
record.includes('## Command') &&
|
|
65
|
-
record.includes('## Result') &&
|
|
66
|
-
record.includes('## Evidence') &&
|
|
67
|
-
/Status:\s*(verified|accepted)/i.test(record)
|
|
68
|
-
|
|
69
|
-
const checks = [
|
|
70
|
-
check('HUI01', 'host UI invocation record template exists', exists('assets/templates/host-ui-invocation-record.md'), 'assets/templates/host-ui-invocation-record.md'),
|
|
71
|
-
check('HUI02', 'portable runner can execute command semantics', commandRun.status === 0 && commandData?.route?.route === 'references/commands.md', '/gse help through run-gse-command.mjs'),
|
|
72
|
-
check('HUI03', 'Claude command adapter is generated at current native path', adapterRun.status === 0 && fs.existsSync(path.join(target, '.claude', 'commands', 'gse.md')) && claudeCommand.includes('Portable execution path'), '.claude/commands/gse.md'),
|
|
73
|
-
check('HUI04', 'Codex command pointer is generated without native claim', adapterRun.status === 0 && fs.existsSync(path.join(target, '.codex', 'gse-command.md')) && codexPointer.includes('not proof of a native project-level /gse slash-command mechanism'), '.codex/gse-command.md'),
|
|
74
|
-
check('HUI05', 'adapter generator labels native support honestly', adapterData?.results?.some((item) => item.host === 'claude' && item.nativeSlashCommand === true) && adapterData?.results?.some((item) => item.host === 'codex' && item.nativeSlashCommand === false), 'generate-command-adapter.mjs result metadata'),
|
|
75
|
-
check('HUI06', 'commands reference requires host runtime evidence', read('references/commands.md').includes('host-specific smoke') && read('references/commands.md').includes('Do not claim native slash-command support unless the current host exposes it and it was verified.'), 'references/commands.md'),
|
|
76
|
-
check('HUI07', 'optional real host invocation record is valid when supplied', recordPath ? recordHasEvidence : true, recordPath ? recordPath : 'no --record supplied; template/readiness only'),
|
|
77
|
-
check('HUI08', 'validator includes host UI invocation audit', read('scripts/validate-gse.mjs').includes('audit-host-ui-invocation.mjs'), 'scripts/validate-gse.mjs'),
|
|
78
|
-
]
|
|
79
|
-
|
|
80
|
-
fs.rmSync(target, { recursive: true, force: true })
|
|
81
|
-
|
|
82
|
-
const passed = checks.filter((item) => item.status === 'passed').length
|
|
83
|
-
const failed = checks.length - passed
|
|
84
|
-
const report = {
|
|
85
|
-
root,
|
|
86
|
-
generatedAt: new Date().toISOString(),
|
|
87
|
-
summary: { status: failed === 0 ? 'passed' : 'failed', passed, failed, total: checks.length },
|
|
88
|
-
workflows: {
|
|
89
|
-
hostUiInvocationReadiness: failed === 0 ? 'verified' : 'failed',
|
|
90
|
-
realHostUiInvocation: recordHasEvidence ? 'verified-by-record' : 'not-verified',
|
|
91
|
-
},
|
|
92
|
-
acceptedBy: recordHasEvidence ? 'host invocation record' : 'not accepted; no real host UI invocation record was supplied',
|
|
93
|
-
limits: [
|
|
94
|
-
'This audit verifies portable command execution, generated host pointers, and the evidence format for real host UI invocation.',
|
|
95
|
-
'Without --record, it does not prove a real Codex, Claude Code, Hermes, WorkBuddy, or other UI invoked the command.',
|
|
96
|
-
'Generated adapters are not runtime proof by themselves.',
|
|
97
|
-
],
|
|
98
|
-
checks,
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
function renderMarkdown(data) {
|
|
102
|
-
const lines = []
|
|
103
|
-
lines.push('# GSE Host UI Invocation Audit')
|
|
104
|
-
lines.push('')
|
|
105
|
-
lines.push('Generated: ' + data.generatedAt)
|
|
106
|
-
lines.push('Root: ' + data.root)
|
|
107
|
-
lines.push('')
|
|
108
|
-
lines.push('## Summary')
|
|
109
|
-
lines.push('')
|
|
110
|
-
lines.push('- Status: ' + data.summary.status)
|
|
111
|
-
lines.push('- Checks: ' + data.summary.passed + '/' + data.summary.total)
|
|
112
|
-
lines.push('- Host UI invocation readiness: ' + data.workflows.hostUiInvocationReadiness)
|
|
113
|
-
lines.push('- Real host UI invocation: ' + data.workflows.realHostUiInvocation)
|
|
114
|
-
lines.push('- Accepted by: ' + data.acceptedBy)
|
|
115
|
-
lines.push('')
|
|
116
|
-
lines.push('## Checks')
|
|
117
|
-
lines.push('')
|
|
118
|
-
for (const item of data.checks) {
|
|
119
|
-
const marker = item.status === 'passed' ? '[x]' : '[ ]'
|
|
120
|
-
lines.push('- ' + marker + ' ' + item.id + ' ' + item.label + ': ' + item.evidence)
|
|
121
|
-
}
|
|
122
|
-
lines.push('')
|
|
123
|
-
lines.push('## Limits')
|
|
124
|
-
lines.push('')
|
|
125
|
-
for (const item of data.limits) lines.push('- ' + item)
|
|
126
|
-
return lines.join('\n') + '\n'
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
if (jsonOnly) console.log(JSON.stringify(report, null, 2))
|
|
130
|
-
else console.log(renderMarkdown(report))
|
|
131
|
-
|
|
132
|
-
if (failed > 0) process.exit(1)
|
|
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 recordPath = readArg('--record')
|
|
17
|
+
const jsonOnly = args.includes('--json')
|
|
18
|
+
|
|
19
|
+
function read(relativePathOrFullPath) {
|
|
20
|
+
const fullPath = path.isAbsolute(relativePathOrFullPath) ? relativePathOrFullPath : path.join(root, relativePathOrFullPath)
|
|
21
|
+
return fs.existsSync(fullPath) ? fs.readFileSync(fullPath, 'utf8').replace(/^\uFEFF/, '') : ''
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function exists(relativePath) {
|
|
25
|
+
return fs.existsSync(path.join(root, relativePath))
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function run(script, commandArgs) {
|
|
29
|
+
const result = spawnSync(process.execPath, [path.join(root, 'scripts', script), ...commandArgs], {
|
|
30
|
+
cwd: root,
|
|
31
|
+
encoding: 'utf8',
|
|
32
|
+
windowsHide: true,
|
|
33
|
+
})
|
|
34
|
+
return {
|
|
35
|
+
command: [process.execPath, path.join(root, 'scripts', script), ...commandArgs].join(' '),
|
|
36
|
+
status: result.status ?? 1,
|
|
37
|
+
stdout: (result.stdout ?? '').trim(),
|
|
38
|
+
stderr: (result.stderr ?? '').trim(),
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function parseJson(text) {
|
|
43
|
+
try { return JSON.parse(text) } catch { return null }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function check(id, label, ok, evidence, risk = '') {
|
|
47
|
+
return { id, label, status: ok ? 'passed' : 'failed', evidence, risk }
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const target = fs.mkdtempSync(path.join(os.tmpdir(), 'gse-host-ui-'))
|
|
51
|
+
fs.mkdirSync(target, { recursive: true })
|
|
52
|
+
fs.writeFileSync(path.join(target, 'AGENTS.md'), '# Host UI Fixture\n', 'utf8')
|
|
53
|
+
const initRun = run('init-project.mjs', ['--target', target, '--mode', 'enterprise', '--json'])
|
|
54
|
+
const adapterRun = run('generate-command-adapter.mjs', ['--target', target, '--host', 'all', '--json'])
|
|
55
|
+
const commandRun = run('run-gse-command.mjs', ['--target', target, '--command', '/gse help', '--json'])
|
|
56
|
+
const adapterData = parseJson(adapterRun.stdout)
|
|
57
|
+
const commandData = parseJson(commandRun.stdout)
|
|
58
|
+
const claudeCommand = read(path.join(target, '.claude', 'commands', 'gse.md'))
|
|
59
|
+
const codexPointer = read(path.join(target, '.codex', 'gse-command.md'))
|
|
60
|
+
const record = recordPath ? read(path.resolve(recordPath)) : ''
|
|
61
|
+
const recordHasEvidence =
|
|
62
|
+
Boolean(record) &&
|
|
63
|
+
record.includes('## Host') &&
|
|
64
|
+
record.includes('## Command') &&
|
|
65
|
+
record.includes('## Result') &&
|
|
66
|
+
record.includes('## Evidence') &&
|
|
67
|
+
/Status:\s*(verified|accepted)/i.test(record)
|
|
68
|
+
|
|
69
|
+
const checks = [
|
|
70
|
+
check('HUI01', 'host UI invocation record template exists', exists('assets/templates/host-ui-invocation-record.md'), 'assets/templates/host-ui-invocation-record.md'),
|
|
71
|
+
check('HUI02', 'portable runner can execute command semantics', commandRun.status === 0 && commandData?.route?.route === 'references/commands.md', '/gse help through run-gse-command.mjs'),
|
|
72
|
+
check('HUI03', 'Claude command adapter is generated at current native path', adapterRun.status === 0 && fs.existsSync(path.join(target, '.claude', 'commands', 'gse.md')) && claudeCommand.includes('Portable execution path'), '.claude/commands/gse.md'),
|
|
73
|
+
check('HUI04', 'Codex command pointer is generated without native claim', adapterRun.status === 0 && fs.existsSync(path.join(target, '.codex', 'gse-command.md')) && codexPointer.includes('not proof of a native project-level /gse slash-command mechanism'), '.codex/gse-command.md'),
|
|
74
|
+
check('HUI05', 'adapter generator labels native support honestly', adapterData?.results?.some((item) => item.host === 'claude' && item.nativeSlashCommand === true) && adapterData?.results?.some((item) => item.host === 'codex' && item.nativeSlashCommand === false), 'generate-command-adapter.mjs result metadata'),
|
|
75
|
+
check('HUI06', 'commands reference requires host runtime evidence', read('references/commands.md').includes('host-specific smoke') && read('references/commands.md').includes('Do not claim native slash-command support unless the current host exposes it and it was verified.'), 'references/commands.md'),
|
|
76
|
+
check('HUI07', 'optional real host invocation record is valid when supplied', recordPath ? recordHasEvidence : true, recordPath ? recordPath : 'no --record supplied; template/readiness only'),
|
|
77
|
+
check('HUI08', 'validator includes host UI invocation audit', read('scripts/validate-gse.mjs').includes('audit-host-ui-invocation.mjs'), 'scripts/validate-gse.mjs'),
|
|
78
|
+
]
|
|
79
|
+
|
|
80
|
+
fs.rmSync(target, { recursive: true, force: true })
|
|
81
|
+
|
|
82
|
+
const passed = checks.filter((item) => item.status === 'passed').length
|
|
83
|
+
const failed = checks.length - passed
|
|
84
|
+
const report = {
|
|
85
|
+
root,
|
|
86
|
+
generatedAt: new Date().toISOString(),
|
|
87
|
+
summary: { status: failed === 0 ? 'passed' : 'failed', passed, failed, total: checks.length },
|
|
88
|
+
workflows: {
|
|
89
|
+
hostUiInvocationReadiness: failed === 0 ? 'verified' : 'failed',
|
|
90
|
+
realHostUiInvocation: recordHasEvidence ? 'verified-by-record' : 'not-verified',
|
|
91
|
+
},
|
|
92
|
+
acceptedBy: recordHasEvidence ? 'host invocation record' : 'not accepted; no real host UI invocation record was supplied',
|
|
93
|
+
limits: [
|
|
94
|
+
'This audit verifies portable command execution, generated host pointers, and the evidence format for real host UI invocation.',
|
|
95
|
+
'Without --record, it does not prove a real Codex, Claude Code, Hermes, WorkBuddy, or other UI invoked the command.',
|
|
96
|
+
'Generated adapters are not runtime proof by themselves.',
|
|
97
|
+
],
|
|
98
|
+
checks,
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function renderMarkdown(data) {
|
|
102
|
+
const lines = []
|
|
103
|
+
lines.push('# GSE Host UI Invocation Audit')
|
|
104
|
+
lines.push('')
|
|
105
|
+
lines.push('Generated: ' + data.generatedAt)
|
|
106
|
+
lines.push('Root: ' + data.root)
|
|
107
|
+
lines.push('')
|
|
108
|
+
lines.push('## Summary')
|
|
109
|
+
lines.push('')
|
|
110
|
+
lines.push('- Status: ' + data.summary.status)
|
|
111
|
+
lines.push('- Checks: ' + data.summary.passed + '/' + data.summary.total)
|
|
112
|
+
lines.push('- Host UI invocation readiness: ' + data.workflows.hostUiInvocationReadiness)
|
|
113
|
+
lines.push('- Real host UI invocation: ' + data.workflows.realHostUiInvocation)
|
|
114
|
+
lines.push('- Accepted by: ' + data.acceptedBy)
|
|
115
|
+
lines.push('')
|
|
116
|
+
lines.push('## Checks')
|
|
117
|
+
lines.push('')
|
|
118
|
+
for (const item of data.checks) {
|
|
119
|
+
const marker = item.status === 'passed' ? '[x]' : '[ ]'
|
|
120
|
+
lines.push('- ' + marker + ' ' + item.id + ' ' + item.label + ': ' + item.evidence)
|
|
121
|
+
}
|
|
122
|
+
lines.push('')
|
|
123
|
+
lines.push('## Limits')
|
|
124
|
+
lines.push('')
|
|
125
|
+
for (const item of data.limits) lines.push('- ' + item)
|
|
126
|
+
return lines.join('\n') + '\n'
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (jsonOnly) console.log(JSON.stringify(report, null, 2))
|
|
130
|
+
else console.log(renderMarkdown(report))
|
|
131
|
+
|
|
132
|
+
if (failed > 0) process.exit(1)
|
|
@@ -0,0 +1,203 @@
|
|
|
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 crypto from 'node:crypto'
|
|
6
|
+
import { spawnSync } from 'node:child_process'
|
|
7
|
+
|
|
8
|
+
const args = process.argv.slice(2)
|
|
9
|
+
|
|
10
|
+
function readArg(name, fallback = null) {
|
|
11
|
+
const index = args.indexOf(name)
|
|
12
|
+
if (index === -1) return fallback
|
|
13
|
+
return args[index + 1] ?? fallback
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const root = path.resolve(readArg('--root', path.join(import.meta.dirname, '..')))
|
|
17
|
+
const installedRootArg = readArg('--installed-root', process.env.GSE_INSTALLED_SKILL_ROOT || null)
|
|
18
|
+
const installedRoot = installedRootArg ? path.resolve(installedRootArg) : null
|
|
19
|
+
const jsonOnly = args.includes('--json')
|
|
20
|
+
|
|
21
|
+
function run(command, commandArgs, cwd = root) {
|
|
22
|
+
const result = spawnSync(command, commandArgs, {
|
|
23
|
+
cwd,
|
|
24
|
+
encoding: 'utf8',
|
|
25
|
+
windowsHide: true,
|
|
26
|
+
})
|
|
27
|
+
return {
|
|
28
|
+
command: [command, ...commandArgs].join(' '),
|
|
29
|
+
status: result.status ?? 1,
|
|
30
|
+
stdout: (result.stdout ?? '').trim(),
|
|
31
|
+
stderr: (result.stderr ?? '').trim(),
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function parseJson(text) {
|
|
36
|
+
try {
|
|
37
|
+
return JSON.parse(text)
|
|
38
|
+
} catch {
|
|
39
|
+
return null
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function exists(relativePath, base = root) {
|
|
44
|
+
return fs.existsSync(path.join(base, relativePath))
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function sha256(filePath) {
|
|
48
|
+
return crypto.createHash('sha256').update(fs.readFileSync(filePath)).digest('hex')
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function check(id, label, ok, evidence, risk = '') {
|
|
52
|
+
return { id, label, status: ok ? 'passed' : 'failed', evidence, risk }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function packageToTemp() {
|
|
56
|
+
const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'gse-installed-sync-'))
|
|
57
|
+
const packageOut = path.join(tempRoot, 'package')
|
|
58
|
+
const packageRun = run(process.execPath, [
|
|
59
|
+
path.join(root, 'scripts', 'package-gse.mjs'),
|
|
60
|
+
'--root',
|
|
61
|
+
root,
|
|
62
|
+
'--out',
|
|
63
|
+
packageOut,
|
|
64
|
+
'--label',
|
|
65
|
+
'installed-sync',
|
|
66
|
+
'--force',
|
|
67
|
+
'--json',
|
|
68
|
+
])
|
|
69
|
+
const manifestPath = path.join(packageOut, 'gse-package-manifest.json')
|
|
70
|
+
const manifest = fs.existsSync(manifestPath) ? parseJson(fs.readFileSync(manifestPath, 'utf8')) : null
|
|
71
|
+
return { tempRoot, packageOut, packageRun, manifest }
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function compareInstalled(manifest, targetRoot) {
|
|
75
|
+
if (!targetRoot) return { compared: 0, missing: [], mismatched: [] }
|
|
76
|
+
const missing = []
|
|
77
|
+
const mismatched = []
|
|
78
|
+
const fileHashes = manifest?.fileHashes ?? {}
|
|
79
|
+
for (const [relativePath, expectedHash] of Object.entries(fileHashes)) {
|
|
80
|
+
const targetPath = path.join(targetRoot, relativePath)
|
|
81
|
+
if (!fs.existsSync(targetPath)) {
|
|
82
|
+
missing.push(relativePath)
|
|
83
|
+
continue
|
|
84
|
+
}
|
|
85
|
+
const actualHash = sha256(targetPath)
|
|
86
|
+
if (actualHash !== expectedHash) mismatched.push(relativePath)
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
compared: Object.keys(fileHashes).length,
|
|
90
|
+
missing,
|
|
91
|
+
mismatched,
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
const { tempRoot, packageOut, packageRun, manifest } = packageToTemp()
|
|
96
|
+
const packageJson = exists('package.json') ? parseJson(fs.readFileSync(path.join(root, 'package.json'), 'utf8')) : null
|
|
97
|
+
const packageCopyJson = exists('package.json', packageOut) ? parseJson(fs.readFileSync(path.join(packageOut, 'package.json'), 'utf8')) : null
|
|
98
|
+
const installedComparison = compareInstalled(manifest, installedRoot)
|
|
99
|
+
const installedCommand = installedRoot
|
|
100
|
+
? run(process.execPath, [
|
|
101
|
+
path.join(installedRoot, 'scripts', 'run-gse-command.mjs'),
|
|
102
|
+
'--root',
|
|
103
|
+
installedRoot,
|
|
104
|
+
'--target',
|
|
105
|
+
installedRoot,
|
|
106
|
+
'--command',
|
|
107
|
+
'/gse maintenance --package-smoke --skip-release-bundle',
|
|
108
|
+
'--json',
|
|
109
|
+
'--compact',
|
|
110
|
+
], installedRoot)
|
|
111
|
+
: null
|
|
112
|
+
const installedCommandData = installedCommand ? parseJson(installedCommand.stdout) : null
|
|
113
|
+
|
|
114
|
+
const requiredPackageFiles = [
|
|
115
|
+
'SKILL.md',
|
|
116
|
+
'package.json',
|
|
117
|
+
'references/commands.md',
|
|
118
|
+
'references/maintenance-cadence.md',
|
|
119
|
+
'scripts/backfill-evidence-levels.mjs',
|
|
120
|
+
'scripts/audit-evidence-review-queue.mjs',
|
|
121
|
+
'scripts/audit-installed-sync.mjs',
|
|
122
|
+
'scripts/audit-session-sync.mjs',
|
|
123
|
+
'scripts/audit-maintenance-snapshot.mjs',
|
|
124
|
+
'scripts/generate-maintenance-snapshot.mjs',
|
|
125
|
+
'scripts/audit-maintenance-cadence.mjs',
|
|
126
|
+
'scripts/record-session-sync.mjs',
|
|
127
|
+
'scripts/run-gse-command.mjs',
|
|
128
|
+
'scripts/validate-gse.mjs',
|
|
129
|
+
]
|
|
130
|
+
|
|
131
|
+
const checks = [
|
|
132
|
+
check('IS01', 'package-gse creates a fresh package manifest', packageRun.status === 0 && manifest?.fileCount > 20 && Boolean(manifest?.integrity?.packageDigest), packageRun.command),
|
|
133
|
+
check('IS02', 'package manifest includes installed sync entrypoint and maintenance command support', manifest?.files?.includes('scripts/audit-installed-sync.mjs') && manifest?.files?.includes('scripts/audit-maintenance-cadence.mjs') && manifest?.files?.includes('references/maintenance-cadence.md'), 'gse-package-manifest.json'),
|
|
134
|
+
check('IS03', 'required package files are present in the package output', requiredPackageFiles.every((file) => exists(file, packageOut)), requiredPackageFiles.join(', ')),
|
|
135
|
+
check('IS04', 'package copy preserves package metadata version', packageJson?.version && packageCopyJson?.version === packageJson.version, `source=${packageJson?.version ?? 'missing'}, package=${packageCopyJson?.version ?? 'missing'}`),
|
|
136
|
+
check('IS05', 'package manifest does not expose the source root', manifest && !JSON.stringify(manifest).includes(root), 'gse-package-manifest.json'),
|
|
137
|
+
installedRoot
|
|
138
|
+
? check('IS06', 'installed root exists and contains GSE entrypoint', exists('SKILL.md', installedRoot) && exists('scripts/run-gse-command.mjs', installedRoot), installedRoot)
|
|
139
|
+
: check('IS06', 'installed root comparison is optional and explicit', true, 'no --installed-root supplied; package self-check only'),
|
|
140
|
+
installedRoot
|
|
141
|
+
? check('IS07', 'installed root matches fresh package file hashes', installedComparison.compared > 20 && installedComparison.missing.length === 0 && installedComparison.mismatched.length === 0, `compared=${installedComparison.compared}, missing=${installedComparison.missing.length}, mismatched=${installedComparison.mismatched.length}`, 'Run the install/sync step again before claiming the installed skill is fresh.')
|
|
142
|
+
: check('IS07', 'installed hash comparison skipped without installed root', true, 'supply --installed-root to compare a real installed copy'),
|
|
143
|
+
installedRoot
|
|
144
|
+
? check('IS08', 'installed copy can run package-only /gse maintenance smoke', installedCommand?.status === 0 && installedCommandData?.summary?.failed === 0, installedCommand?.command ?? 'not run')
|
|
145
|
+
: check('IS08', 'installed command smoke skipped without installed root', true, 'supply --installed-root to run installed command smoke'),
|
|
146
|
+
]
|
|
147
|
+
|
|
148
|
+
const passed = checks.filter((item) => item.status === 'passed').length
|
|
149
|
+
const failed = checks.length - passed
|
|
150
|
+
const report = {
|
|
151
|
+
root,
|
|
152
|
+
installedRoot,
|
|
153
|
+
generatedAt: new Date().toISOString(),
|
|
154
|
+
tempRoot,
|
|
155
|
+
summary: { status: failed === 0 ? 'passed' : 'failed', passed, failed, total: checks.length },
|
|
156
|
+
workflows: {
|
|
157
|
+
freshPackage: packageRun.status === 0 ? 'verified' : 'failed',
|
|
158
|
+
installedSync: installedRoot ? failed === 0 ? 'verified' : 'failed' : 'not-requested',
|
|
159
|
+
installedCommandSmoke: installedRoot ? installedCommand?.status === 0 ? 'verified' : 'failed' : 'not-requested',
|
|
160
|
+
},
|
|
161
|
+
comparison: installedComparison,
|
|
162
|
+
limits: [
|
|
163
|
+
'Without --installed-root this audit verifies fresh package contents only.',
|
|
164
|
+
'With --installed-root it compares every packaged file hash against the installed copy and runs a package-only /gse maintenance smoke from that installed copy.',
|
|
165
|
+
'This audit does not publish a package, update npm, or prove native host slash-command support.',
|
|
166
|
+
],
|
|
167
|
+
checks,
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
function renderMarkdown(data) {
|
|
171
|
+
const lines = []
|
|
172
|
+
lines.push('# GSE Installed Sync Audit')
|
|
173
|
+
lines.push('')
|
|
174
|
+
lines.push('Generated: ' + data.generatedAt)
|
|
175
|
+
lines.push('Root: ' + data.root)
|
|
176
|
+
lines.push('Installed root: ' + (data.installedRoot ?? 'not provided'))
|
|
177
|
+
lines.push('')
|
|
178
|
+
lines.push('## Summary')
|
|
179
|
+
lines.push('')
|
|
180
|
+
lines.push('- Status: ' + data.summary.status)
|
|
181
|
+
lines.push('- Checks: ' + data.summary.passed + '/' + data.summary.total)
|
|
182
|
+
lines.push('- Fresh package: ' + data.workflows.freshPackage)
|
|
183
|
+
lines.push('- Installed sync: ' + data.workflows.installedSync)
|
|
184
|
+
lines.push('')
|
|
185
|
+
lines.push('## Checks')
|
|
186
|
+
lines.push('')
|
|
187
|
+
for (const item of data.checks) {
|
|
188
|
+
const marker = item.status === 'passed' ? '[x]' : '[ ]'
|
|
189
|
+
lines.push('- ' + marker + ' ' + item.id + ' ' + item.label + ': ' + item.evidence)
|
|
190
|
+
}
|
|
191
|
+
lines.push('')
|
|
192
|
+
lines.push('## Limits')
|
|
193
|
+
lines.push('')
|
|
194
|
+
for (const item of data.limits) lines.push('- ' + item)
|
|
195
|
+
return lines.join('\n') + '\n'
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
if (jsonOnly) console.log(JSON.stringify(report, null, 2))
|
|
199
|
+
else console.log(renderMarkdown(report))
|
|
200
|
+
|
|
201
|
+
fs.rmSync(tempRoot, { recursive: true, force: true })
|
|
202
|
+
|
|
203
|
+
if (failed > 0) process.exit(1)
|