@t275005746/gse 0.1.0 → 0.1.1
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 +3 -4
- package/CHANGELOG.md +24 -24
- package/CONTRIBUTING.md +64 -64
- package/LICENSE +21 -21
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/SECURITY.md +41 -41
- 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 +104 -104
- package/assets/templates/evidence.md +14 -14
- 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/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 +53 -53
- package/references/adoption-recipes.md +171 -171
- package/references/agent-roles.md +49 -49
- package/references/architecture-health.md +101 -101
- package/references/benchmark-audit.md +73 -73
- 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 -81
- package/references/evidence-taxonomy.md +123 -123
- package/references/file-ownership.md +107 -107
- 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 +119 -119
- package/references/learning-system.md +35 -35
- 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-profile.md +57 -57
- package/references/public-release.md +174 -174
- package/references/quality-gates.md +100 -100
- 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/router.md +90 -90
- package/references/spec-workflow.md +66 -66
- package/references/task-levels.md +81 -81
- package/references/tool-adapters.md +73 -73
- 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.mjs +323 -323
- package/scripts/audit-command-adapters.mjs +91 -91
- package/scripts/audit-command-execution.mjs +210 -210
- package/scripts/audit-compatibility.mjs +149 -149
- package/scripts/audit-completion-readiness.mjs +292 -292
- package/scripts/audit-distribution.mjs +251 -251
- package/scripts/audit-domain-quality-gates.mjs +108 -108
- package/scripts/audit-evidence-placeholders.mjs +126 -126
- 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-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-marketplace-discovery.mjs +122 -122
- package/scripts/audit-npm-package-metadata.mjs +155 -155
- package/scripts/audit-npm-publish-dry-run.mjs +191 -169
- package/scripts/audit-npm-tarball-install.mjs +191 -191
- package/scripts/audit-open-source-defaults.mjs +92 -92
- package/scripts/audit-open-source-readiness.mjs +97 -97
- package/scripts/audit-project.mjs +138 -138
- package/scripts/audit-public-acceptance-command-dry-run-drill.mjs +203 -203
- package/scripts/audit-public-acceptance-readiness.mjs +224 -224
- 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-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-readiness.mjs +106 -106
- package/scripts/audit-release-trust.mjs +62 -62
- package/scripts/audit-remote-distribution.mjs +266 -266
- package/scripts/audit-roadmap-consistency.mjs +235 -235
- package/scripts/audit-signing.mjs +147 -147
- package/scripts/audit-state-freshness.mjs +14 -9
- package/scripts/audit-target-adoption-evidence.mjs +117 -117
- package/scripts/audit-target-project.mjs +507 -507
- 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 -125
- 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-final-acceptance-packet.mjs +181 -181
- package/scripts/generate-final-form-progress-report.mjs +205 -205
- package/scripts/generate-host-runtime-evidence-handoff.mjs +206 -206
- package/scripts/generate-owner-external-gate-kit.mjs +295 -295
- package/scripts/generate-public-acceptance-handoff.mjs +168 -168
- 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 -172
- package/scripts/generate-release-status-manifest.mjs +200 -200
- 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 +785 -785
- 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-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/sign-gse-package.mjs +83 -83
- package/scripts/update-project-state.mjs +223 -223
- package/scripts/verify-gse-package.mjs +85 -85
|
@@ -1,307 +1,307 @@
|
|
|
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 target = path.resolve(readArg('--target', process.cwd()))
|
|
14
|
-
const write = args.includes('--write')
|
|
15
|
-
const force = args.includes('--force')
|
|
16
|
-
const json = args.includes('--json')
|
|
17
|
-
const profilePath = path.join(target, '.gse', 'project-profile.md')
|
|
18
|
-
|
|
19
|
-
function exists(relativePath) {
|
|
20
|
-
return fs.existsSync(path.join(target, relativePath))
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function readText(relativePath) {
|
|
24
|
-
const filePath = path.join(target, relativePath)
|
|
25
|
-
if (!fs.existsSync(filePath)) return null
|
|
26
|
-
return fs.readFileSync(filePath, 'utf8')
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function safeJson(relativePath) {
|
|
30
|
-
const text = readText(relativePath)
|
|
31
|
-
if (!text) return null
|
|
32
|
-
try {
|
|
33
|
-
return JSON.parse(text.replace(/^\uFEFF/, ''))
|
|
34
|
-
} catch {
|
|
35
|
-
return null
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
function listExisting(paths) {
|
|
40
|
-
return paths.filter((item) => exists(item))
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function detectPackageManager() {
|
|
44
|
-
if (exists('pnpm-lock.yaml')) return 'pnpm'
|
|
45
|
-
if (exists('bun.lockb') || exists('bun.lock')) return 'bun'
|
|
46
|
-
if (exists('yarn.lock')) return 'yarn'
|
|
47
|
-
if (exists('package-lock.json')) return 'npm'
|
|
48
|
-
if (exists('package.json')) return 'npm or project-specific'
|
|
49
|
-
return ''
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
function detectFrameworks(pkg) {
|
|
53
|
-
if (!pkg) return []
|
|
54
|
-
const deps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }
|
|
55
|
-
const frameworks = []
|
|
56
|
-
const checks = [
|
|
57
|
-
['next', 'Next.js'],
|
|
58
|
-
['react', 'React'],
|
|
59
|
-
['vite', 'Vite'],
|
|
60
|
-
['vue', 'Vue'],
|
|
61
|
-
['svelte', 'Svelte'],
|
|
62
|
-
['typescript', 'TypeScript'],
|
|
63
|
-
['playwright', 'Playwright'],
|
|
64
|
-
['@playwright/test', 'Playwright'],
|
|
65
|
-
['vitest', 'Vitest'],
|
|
66
|
-
['jest', 'Jest'],
|
|
67
|
-
['eslint', 'ESLint'],
|
|
68
|
-
['prettier', 'Prettier'],
|
|
69
|
-
]
|
|
70
|
-
for (const [dep, label] of checks) {
|
|
71
|
-
if (deps[dep] && !frameworks.includes(label)) frameworks.push(label)
|
|
72
|
-
}
|
|
73
|
-
return frameworks
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
function detectScripts(pkg) {
|
|
77
|
-
const scripts = pkg?.scripts ?? {}
|
|
78
|
-
const wanted = ['install', 'dev', 'start', 'test', 'test:unit', 'test:e2e', 'lint', 'typecheck', 'check', 'build', 'format']
|
|
79
|
-
const names = new Set(wanted.filter((name) => scripts[name]))
|
|
80
|
-
for (const name of Object.keys(scripts)) {
|
|
81
|
-
if (/^(smoke|evidence|replay|eval|release|deploy|publish|electron):/.test(name)) names.add(name)
|
|
82
|
-
}
|
|
83
|
-
return [...names]
|
|
84
|
-
.filter((name) => scripts[name])
|
|
85
|
-
.map((name) => ({ name, command: scripts[name] }))
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function detectWorkflows() {
|
|
89
|
-
const dir = path.join(target, '.github', 'workflows')
|
|
90
|
-
if (!fs.existsSync(dir)) return []
|
|
91
|
-
return fs.readdirSync(dir).filter((name) => /\.ya?ml$/i.test(name)).map((name) => `.github/workflows/${name}`)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
function detectMcpFiles() {
|
|
95
|
-
return listExisting([
|
|
96
|
-
'.mcp.json',
|
|
97
|
-
'mcp.json',
|
|
98
|
-
'.cursor/mcp.json',
|
|
99
|
-
'.claude/mcp.json',
|
|
100
|
-
'.codex/mcp.json',
|
|
101
|
-
])
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
function detectAgentRules() {
|
|
105
|
-
return listExisting([
|
|
106
|
-
'AGENTS.md',
|
|
107
|
-
'CLAUDE.md',
|
|
108
|
-
'GEMINI.md',
|
|
109
|
-
'CONTEXT.md',
|
|
110
|
-
'CONTEXT-MAP.md',
|
|
111
|
-
'.cursorrules',
|
|
112
|
-
'.windsurfrules',
|
|
113
|
-
])
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
function detectDocs() {
|
|
117
|
-
return listExisting([
|
|
118
|
-
'README.md',
|
|
119
|
-
'CONTRIBUTING.md',
|
|
120
|
-
'CODING_STANDARDS.md',
|
|
121
|
-
'SECURITY.md',
|
|
122
|
-
'CHANGELOG.md',
|
|
123
|
-
'docs/adr',
|
|
124
|
-
'docs/architecture.md',
|
|
125
|
-
])
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
function detectConfigFiles() {
|
|
129
|
-
return listExisting([
|
|
130
|
-
'package.json',
|
|
131
|
-
'tsconfig.json',
|
|
132
|
-
'Makefile',
|
|
133
|
-
'justfile',
|
|
134
|
-
'pyproject.toml',
|
|
135
|
-
'Cargo.toml',
|
|
136
|
-
'go.mod',
|
|
137
|
-
'playwright.config.ts',
|
|
138
|
-
'playwright.config.js',
|
|
139
|
-
'vite.config.ts',
|
|
140
|
-
'vite.config.js',
|
|
141
|
-
'next.config.js',
|
|
142
|
-
'eslint.config.js',
|
|
143
|
-
'eslint.config.mjs',
|
|
144
|
-
'.prettierrc',
|
|
145
|
-
'.pre-commit-config.yaml',
|
|
146
|
-
'.env.example',
|
|
147
|
-
])
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
function inferRepoType(pkg, configs) {
|
|
151
|
-
if (pkg) return 'JavaScript/TypeScript package or web app'
|
|
152
|
-
if (configs.includes('pyproject.toml')) return 'Python project'
|
|
153
|
-
if (configs.includes('Cargo.toml')) return 'Rust project'
|
|
154
|
-
if (configs.includes('go.mod')) return 'Go project'
|
|
155
|
-
return 'unknown'
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function table(rows) {
|
|
159
|
-
if (rows.length === 0) return '| Item | Value | Status | Evidence |\n|---|---|---|---|\n| - | - | unknown | - |'
|
|
160
|
-
return ['| Item | Value | Status | Evidence |', '|---|---|---|---|', ...rows.map((row) => `| ${row.item} | ${row.value} | ${row.status} | ${row.evidence} |`)].join('\n')
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
function renderMarkdown(model) {
|
|
164
|
-
const scriptLines = model.scripts.length
|
|
165
|
-
? model.scripts.map((item) => `- ${item.name}: \`${item.command}\` (documented in package.json)`).join('\n')
|
|
166
|
-
: '- No package scripts detected.'
|
|
167
|
-
|
|
168
|
-
const toolRows = [
|
|
169
|
-
...model.toolConnections.map((item) => ({
|
|
170
|
-
item: item.tool,
|
|
171
|
-
value: item.purpose,
|
|
172
|
-
status: item.status,
|
|
173
|
-
evidence: item.evidence,
|
|
174
|
-
})),
|
|
175
|
-
]
|
|
176
|
-
|
|
177
|
-
return `# Project Profile
|
|
178
|
-
|
|
179
|
-
Generated: ${model.generatedAt}
|
|
180
|
-
|
|
181
|
-
Keep this file short and factual. Project-specific rules override generic GSE defaults.
|
|
182
|
-
|
|
183
|
-
## Identity
|
|
184
|
-
|
|
185
|
-
- Product/system name: ${model.identity.name}
|
|
186
|
-
- Repository type: ${model.identity.repoType}
|
|
187
|
-
- Main languages/frameworks: ${model.identity.frameworks.length ? model.identity.frameworks.join(', ') : 'unknown'}
|
|
188
|
-
- Package manager: ${model.identity.packageManager || 'unknown'}
|
|
189
|
-
|
|
190
|
-
## Evidence Sources
|
|
191
|
-
|
|
192
|
-
- Agent rules: ${model.sources.agentRules.length ? model.sources.agentRules.join(', ') : '-'}
|
|
193
|
-
- Docs: ${model.sources.docs.length ? model.sources.docs.join(', ') : '-'}
|
|
194
|
-
- Config files: ${model.sources.configFiles.length ? model.sources.configFiles.join(', ') : '-'}
|
|
195
|
-
- CI workflows: ${model.sources.workflows.length ? model.sources.workflows.join(', ') : '-'}
|
|
196
|
-
|
|
197
|
-
## Development Commands
|
|
198
|
-
|
|
199
|
-
${scriptLines}
|
|
200
|
-
|
|
201
|
-
## Standards
|
|
202
|
-
|
|
203
|
-
- Coding standards: ${model.sources.docs.includes('CODING_STANDARDS.md') ? 'documented in CODING_STANDARDS.md' : 'unknown'}
|
|
204
|
-
- Formatting: ${model.formatting.length ? model.formatting.join(', ') : 'unknown'}
|
|
205
|
-
- Testing expectations: ${model.testing.length ? model.testing.join(', ') : 'unknown'}
|
|
206
|
-
- Documentation expectations: ${model.sources.docs.includes('CONTRIBUTING.md') ? 'documented in CONTRIBUTING.md' : 'unknown'}
|
|
207
|
-
|
|
208
|
-
## Tool Connections
|
|
209
|
-
|
|
210
|
-
${table(toolRows)}
|
|
211
|
-
|
|
212
|
-
## Agent Host Adapters
|
|
213
|
-
|
|
214
|
-
- Codex: ${model.sources.agentRules.includes('AGENTS.md') ? 'documented via AGENTS.md' : 'unknown'}
|
|
215
|
-
- Claude Code: ${model.sources.agentRules.includes('CLAUDE.md') || exists('.claude') ? 'documented' : 'unknown'}
|
|
216
|
-
- Hermes/AION-style runtime: unknown
|
|
217
|
-
- WorkBuddy/other: unknown
|
|
218
|
-
|
|
219
|
-
## Security And Permissions
|
|
220
|
-
|
|
221
|
-
- Secrets handling: ${model.sources.configFiles.includes('.env.example') ? 'documented by .env.example presence; real secrets not inspected' : 'unknown'}
|
|
222
|
-
- Write-capable tools: unknown
|
|
223
|
-
- Destructive commands: unknown
|
|
224
|
-
- External services: ${model.externalServices.length ? model.externalServices.join(', ') : 'unknown'}
|
|
225
|
-
|
|
226
|
-
## Release And Rollback
|
|
227
|
-
|
|
228
|
-
- Release command/process: ${model.release.length ? model.release.join(', ') : 'unknown'}
|
|
229
|
-
- Rollback: unknown
|
|
230
|
-
- Smoke checks: ${model.smoke.length ? model.smoke.join(', ') : 'unknown'}
|
|
231
|
-
|
|
232
|
-
## Known Gotchas
|
|
233
|
-
|
|
234
|
-
- Tool presence from config is marked documented, not verified. Run focused commands before relying on any tool.
|
|
235
|
-
`
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
const pkg = safeJson('package.json')
|
|
239
|
-
const deps = { ...(pkg?.dependencies ?? {}), ...(pkg?.devDependencies ?? {}) }
|
|
240
|
-
const configs = detectConfigFiles()
|
|
241
|
-
const workflows = detectWorkflows()
|
|
242
|
-
const scripts = detectScripts(pkg)
|
|
243
|
-
const frameworks = detectFrameworks(pkg)
|
|
244
|
-
const mcpFiles = detectMcpFiles()
|
|
245
|
-
const agentRules = detectAgentRules()
|
|
246
|
-
const docs = detectDocs()
|
|
247
|
-
|
|
248
|
-
const formatting = []
|
|
249
|
-
if (configs.some((item) => item.includes('prettier'))) formatting.push('Prettier documented by config')
|
|
250
|
-
if (configs.some((item) => item.includes('eslint'))) formatting.push('ESLint documented by config')
|
|
251
|
-
|
|
252
|
-
const testing = []
|
|
253
|
-
for (const script of scripts) {
|
|
254
|
-
if (script.name.includes('test')) testing.push(`${script.name} script documented`)
|
|
255
|
-
}
|
|
256
|
-
if (configs.some((item) => item.startsWith('playwright.config'))) testing.push('Playwright config documented')
|
|
257
|
-
|
|
258
|
-
const toolConnections = []
|
|
259
|
-
if (mcpFiles.length) toolConnections.push({ tool: 'MCP', purpose: 'External tool/data connections', status: 'documented', evidence: mcpFiles.join(', ') })
|
|
260
|
-
else toolConnections.push({ tool: 'MCP', purpose: 'External tool/data connections', status: 'unknown', evidence: '-' })
|
|
261
|
-
const playwrightEvidence = []
|
|
262
|
-
if (deps.playwright || deps['@playwright/test']) playwrightEvidence.push('package.json dependency')
|
|
263
|
-
if (scripts.some((item) => item.name.includes('smoke') && /browser|ui|playwright/i.test(item.command + ' ' + item.name))) playwrightEvidence.push('package.json smoke script')
|
|
264
|
-
if (configs.some((item) => item.startsWith('playwright.config'))) playwrightEvidence.push(configs.filter((item) => item.startsWith('playwright.config')).join(', '))
|
|
265
|
-
if (playwrightEvidence.length) toolConnections.push({ tool: 'Browser/Playwright', purpose: 'UI smoke and browser automation', status: 'documented', evidence: playwrightEvidence.join(', ') })
|
|
266
|
-
else toolConnections.push({ tool: 'Browser/Playwright', purpose: 'UI smoke and browser automation', status: 'unknown', evidence: '-' })
|
|
267
|
-
if (workflows.length) toolConnections.push({ tool: 'CI', purpose: 'Automated gates', status: 'documented', evidence: workflows.join(', ') })
|
|
268
|
-
else toolConnections.push({ tool: 'CI', purpose: 'Automated gates', status: 'unknown', evidence: '-' })
|
|
269
|
-
toolConnections.push({ tool: 'LSP/index', purpose: 'Symbol navigation', status: 'unknown', evidence: '-' })
|
|
270
|
-
|
|
271
|
-
const release = scripts.filter((item) => /release|deploy|publish/i.test(item.name)).map((item) => `${item.name}: ${item.command}`)
|
|
272
|
-
const smoke = scripts.filter((item) => /smoke|check|test:e2e/i.test(item.name)).map((item) => `${item.name}: ${item.command}`)
|
|
273
|
-
const externalServices = []
|
|
274
|
-
if (configs.includes('.env.example')) externalServices.push('.env.example present')
|
|
275
|
-
|
|
276
|
-
const model = {
|
|
277
|
-
target,
|
|
278
|
-
generatedAt: new Date().toISOString(),
|
|
279
|
-
identity: {
|
|
280
|
-
name: pkg?.name ?? path.basename(target),
|
|
281
|
-
repoType: inferRepoType(pkg, configs),
|
|
282
|
-
frameworks,
|
|
283
|
-
packageManager: detectPackageManager(),
|
|
284
|
-
},
|
|
285
|
-
sources: { agentRules, docs, configFiles: configs, workflows },
|
|
286
|
-
scripts,
|
|
287
|
-
formatting,
|
|
288
|
-
testing,
|
|
289
|
-
toolConnections,
|
|
290
|
-
release,
|
|
291
|
-
smoke,
|
|
292
|
-
externalServices,
|
|
293
|
-
}
|
|
294
|
-
|
|
295
|
-
const markdown = renderMarkdown(model)
|
|
296
|
-
|
|
297
|
-
if (write) {
|
|
298
|
-
fs.mkdirSync(path.dirname(profilePath), { recursive: true })
|
|
299
|
-
if (!force && fs.existsSync(profilePath)) {
|
|
300
|
-
console.error(`Refusing to overwrite existing ${profilePath}. Pass --force to overwrite.`)
|
|
301
|
-
process.exit(2)
|
|
302
|
-
}
|
|
303
|
-
fs.writeFileSync(profilePath, markdown, 'utf8')
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
if (json) console.log(JSON.stringify(model, null, 2))
|
|
307
|
-
else console.log(markdown)
|
|
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 target = path.resolve(readArg('--target', process.cwd()))
|
|
14
|
+
const write = args.includes('--write')
|
|
15
|
+
const force = args.includes('--force')
|
|
16
|
+
const json = args.includes('--json')
|
|
17
|
+
const profilePath = path.join(target, '.gse', 'project-profile.md')
|
|
18
|
+
|
|
19
|
+
function exists(relativePath) {
|
|
20
|
+
return fs.existsSync(path.join(target, relativePath))
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function readText(relativePath) {
|
|
24
|
+
const filePath = path.join(target, relativePath)
|
|
25
|
+
if (!fs.existsSync(filePath)) return null
|
|
26
|
+
return fs.readFileSync(filePath, 'utf8')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function safeJson(relativePath) {
|
|
30
|
+
const text = readText(relativePath)
|
|
31
|
+
if (!text) return null
|
|
32
|
+
try {
|
|
33
|
+
return JSON.parse(text.replace(/^\uFEFF/, ''))
|
|
34
|
+
} catch {
|
|
35
|
+
return null
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function listExisting(paths) {
|
|
40
|
+
return paths.filter((item) => exists(item))
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function detectPackageManager() {
|
|
44
|
+
if (exists('pnpm-lock.yaml')) return 'pnpm'
|
|
45
|
+
if (exists('bun.lockb') || exists('bun.lock')) return 'bun'
|
|
46
|
+
if (exists('yarn.lock')) return 'yarn'
|
|
47
|
+
if (exists('package-lock.json')) return 'npm'
|
|
48
|
+
if (exists('package.json')) return 'npm or project-specific'
|
|
49
|
+
return ''
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function detectFrameworks(pkg) {
|
|
53
|
+
if (!pkg) return []
|
|
54
|
+
const deps = { ...(pkg.dependencies ?? {}), ...(pkg.devDependencies ?? {}) }
|
|
55
|
+
const frameworks = []
|
|
56
|
+
const checks = [
|
|
57
|
+
['next', 'Next.js'],
|
|
58
|
+
['react', 'React'],
|
|
59
|
+
['vite', 'Vite'],
|
|
60
|
+
['vue', 'Vue'],
|
|
61
|
+
['svelte', 'Svelte'],
|
|
62
|
+
['typescript', 'TypeScript'],
|
|
63
|
+
['playwright', 'Playwright'],
|
|
64
|
+
['@playwright/test', 'Playwright'],
|
|
65
|
+
['vitest', 'Vitest'],
|
|
66
|
+
['jest', 'Jest'],
|
|
67
|
+
['eslint', 'ESLint'],
|
|
68
|
+
['prettier', 'Prettier'],
|
|
69
|
+
]
|
|
70
|
+
for (const [dep, label] of checks) {
|
|
71
|
+
if (deps[dep] && !frameworks.includes(label)) frameworks.push(label)
|
|
72
|
+
}
|
|
73
|
+
return frameworks
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function detectScripts(pkg) {
|
|
77
|
+
const scripts = pkg?.scripts ?? {}
|
|
78
|
+
const wanted = ['install', 'dev', 'start', 'test', 'test:unit', 'test:e2e', 'lint', 'typecheck', 'check', 'build', 'format']
|
|
79
|
+
const names = new Set(wanted.filter((name) => scripts[name]))
|
|
80
|
+
for (const name of Object.keys(scripts)) {
|
|
81
|
+
if (/^(smoke|evidence|replay|eval|release|deploy|publish|electron):/.test(name)) names.add(name)
|
|
82
|
+
}
|
|
83
|
+
return [...names]
|
|
84
|
+
.filter((name) => scripts[name])
|
|
85
|
+
.map((name) => ({ name, command: scripts[name] }))
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function detectWorkflows() {
|
|
89
|
+
const dir = path.join(target, '.github', 'workflows')
|
|
90
|
+
if (!fs.existsSync(dir)) return []
|
|
91
|
+
return fs.readdirSync(dir).filter((name) => /\.ya?ml$/i.test(name)).map((name) => `.github/workflows/${name}`)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function detectMcpFiles() {
|
|
95
|
+
return listExisting([
|
|
96
|
+
'.mcp.json',
|
|
97
|
+
'mcp.json',
|
|
98
|
+
'.cursor/mcp.json',
|
|
99
|
+
'.claude/mcp.json',
|
|
100
|
+
'.codex/mcp.json',
|
|
101
|
+
])
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function detectAgentRules() {
|
|
105
|
+
return listExisting([
|
|
106
|
+
'AGENTS.md',
|
|
107
|
+
'CLAUDE.md',
|
|
108
|
+
'GEMINI.md',
|
|
109
|
+
'CONTEXT.md',
|
|
110
|
+
'CONTEXT-MAP.md',
|
|
111
|
+
'.cursorrules',
|
|
112
|
+
'.windsurfrules',
|
|
113
|
+
])
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function detectDocs() {
|
|
117
|
+
return listExisting([
|
|
118
|
+
'README.md',
|
|
119
|
+
'CONTRIBUTING.md',
|
|
120
|
+
'CODING_STANDARDS.md',
|
|
121
|
+
'SECURITY.md',
|
|
122
|
+
'CHANGELOG.md',
|
|
123
|
+
'docs/adr',
|
|
124
|
+
'docs/architecture.md',
|
|
125
|
+
])
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function detectConfigFiles() {
|
|
129
|
+
return listExisting([
|
|
130
|
+
'package.json',
|
|
131
|
+
'tsconfig.json',
|
|
132
|
+
'Makefile',
|
|
133
|
+
'justfile',
|
|
134
|
+
'pyproject.toml',
|
|
135
|
+
'Cargo.toml',
|
|
136
|
+
'go.mod',
|
|
137
|
+
'playwright.config.ts',
|
|
138
|
+
'playwright.config.js',
|
|
139
|
+
'vite.config.ts',
|
|
140
|
+
'vite.config.js',
|
|
141
|
+
'next.config.js',
|
|
142
|
+
'eslint.config.js',
|
|
143
|
+
'eslint.config.mjs',
|
|
144
|
+
'.prettierrc',
|
|
145
|
+
'.pre-commit-config.yaml',
|
|
146
|
+
'.env.example',
|
|
147
|
+
])
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function inferRepoType(pkg, configs) {
|
|
151
|
+
if (pkg) return 'JavaScript/TypeScript package or web app'
|
|
152
|
+
if (configs.includes('pyproject.toml')) return 'Python project'
|
|
153
|
+
if (configs.includes('Cargo.toml')) return 'Rust project'
|
|
154
|
+
if (configs.includes('go.mod')) return 'Go project'
|
|
155
|
+
return 'unknown'
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function table(rows) {
|
|
159
|
+
if (rows.length === 0) return '| Item | Value | Status | Evidence |\n|---|---|---|---|\n| - | - | unknown | - |'
|
|
160
|
+
return ['| Item | Value | Status | Evidence |', '|---|---|---|---|', ...rows.map((row) => `| ${row.item} | ${row.value} | ${row.status} | ${row.evidence} |`)].join('\n')
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
function renderMarkdown(model) {
|
|
164
|
+
const scriptLines = model.scripts.length
|
|
165
|
+
? model.scripts.map((item) => `- ${item.name}: \`${item.command}\` (documented in package.json)`).join('\n')
|
|
166
|
+
: '- No package scripts detected.'
|
|
167
|
+
|
|
168
|
+
const toolRows = [
|
|
169
|
+
...model.toolConnections.map((item) => ({
|
|
170
|
+
item: item.tool,
|
|
171
|
+
value: item.purpose,
|
|
172
|
+
status: item.status,
|
|
173
|
+
evidence: item.evidence,
|
|
174
|
+
})),
|
|
175
|
+
]
|
|
176
|
+
|
|
177
|
+
return `# Project Profile
|
|
178
|
+
|
|
179
|
+
Generated: ${model.generatedAt}
|
|
180
|
+
|
|
181
|
+
Keep this file short and factual. Project-specific rules override generic GSE defaults.
|
|
182
|
+
|
|
183
|
+
## Identity
|
|
184
|
+
|
|
185
|
+
- Product/system name: ${model.identity.name}
|
|
186
|
+
- Repository type: ${model.identity.repoType}
|
|
187
|
+
- Main languages/frameworks: ${model.identity.frameworks.length ? model.identity.frameworks.join(', ') : 'unknown'}
|
|
188
|
+
- Package manager: ${model.identity.packageManager || 'unknown'}
|
|
189
|
+
|
|
190
|
+
## Evidence Sources
|
|
191
|
+
|
|
192
|
+
- Agent rules: ${model.sources.agentRules.length ? model.sources.agentRules.join(', ') : '-'}
|
|
193
|
+
- Docs: ${model.sources.docs.length ? model.sources.docs.join(', ') : '-'}
|
|
194
|
+
- Config files: ${model.sources.configFiles.length ? model.sources.configFiles.join(', ') : '-'}
|
|
195
|
+
- CI workflows: ${model.sources.workflows.length ? model.sources.workflows.join(', ') : '-'}
|
|
196
|
+
|
|
197
|
+
## Development Commands
|
|
198
|
+
|
|
199
|
+
${scriptLines}
|
|
200
|
+
|
|
201
|
+
## Standards
|
|
202
|
+
|
|
203
|
+
- Coding standards: ${model.sources.docs.includes('CODING_STANDARDS.md') ? 'documented in CODING_STANDARDS.md' : 'unknown'}
|
|
204
|
+
- Formatting: ${model.formatting.length ? model.formatting.join(', ') : 'unknown'}
|
|
205
|
+
- Testing expectations: ${model.testing.length ? model.testing.join(', ') : 'unknown'}
|
|
206
|
+
- Documentation expectations: ${model.sources.docs.includes('CONTRIBUTING.md') ? 'documented in CONTRIBUTING.md' : 'unknown'}
|
|
207
|
+
|
|
208
|
+
## Tool Connections
|
|
209
|
+
|
|
210
|
+
${table(toolRows)}
|
|
211
|
+
|
|
212
|
+
## Agent Host Adapters
|
|
213
|
+
|
|
214
|
+
- Codex: ${model.sources.agentRules.includes('AGENTS.md') ? 'documented via AGENTS.md' : 'unknown'}
|
|
215
|
+
- Claude Code: ${model.sources.agentRules.includes('CLAUDE.md') || exists('.claude') ? 'documented' : 'unknown'}
|
|
216
|
+
- Hermes/AION-style runtime: unknown
|
|
217
|
+
- WorkBuddy/other: unknown
|
|
218
|
+
|
|
219
|
+
## Security And Permissions
|
|
220
|
+
|
|
221
|
+
- Secrets handling: ${model.sources.configFiles.includes('.env.example') ? 'documented by .env.example presence; real secrets not inspected' : 'unknown'}
|
|
222
|
+
- Write-capable tools: unknown
|
|
223
|
+
- Destructive commands: unknown
|
|
224
|
+
- External services: ${model.externalServices.length ? model.externalServices.join(', ') : 'unknown'}
|
|
225
|
+
|
|
226
|
+
## Release And Rollback
|
|
227
|
+
|
|
228
|
+
- Release command/process: ${model.release.length ? model.release.join(', ') : 'unknown'}
|
|
229
|
+
- Rollback: unknown
|
|
230
|
+
- Smoke checks: ${model.smoke.length ? model.smoke.join(', ') : 'unknown'}
|
|
231
|
+
|
|
232
|
+
## Known Gotchas
|
|
233
|
+
|
|
234
|
+
- Tool presence from config is marked documented, not verified. Run focused commands before relying on any tool.
|
|
235
|
+
`
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const pkg = safeJson('package.json')
|
|
239
|
+
const deps = { ...(pkg?.dependencies ?? {}), ...(pkg?.devDependencies ?? {}) }
|
|
240
|
+
const configs = detectConfigFiles()
|
|
241
|
+
const workflows = detectWorkflows()
|
|
242
|
+
const scripts = detectScripts(pkg)
|
|
243
|
+
const frameworks = detectFrameworks(pkg)
|
|
244
|
+
const mcpFiles = detectMcpFiles()
|
|
245
|
+
const agentRules = detectAgentRules()
|
|
246
|
+
const docs = detectDocs()
|
|
247
|
+
|
|
248
|
+
const formatting = []
|
|
249
|
+
if (configs.some((item) => item.includes('prettier'))) formatting.push('Prettier documented by config')
|
|
250
|
+
if (configs.some((item) => item.includes('eslint'))) formatting.push('ESLint documented by config')
|
|
251
|
+
|
|
252
|
+
const testing = []
|
|
253
|
+
for (const script of scripts) {
|
|
254
|
+
if (script.name.includes('test')) testing.push(`${script.name} script documented`)
|
|
255
|
+
}
|
|
256
|
+
if (configs.some((item) => item.startsWith('playwright.config'))) testing.push('Playwright config documented')
|
|
257
|
+
|
|
258
|
+
const toolConnections = []
|
|
259
|
+
if (mcpFiles.length) toolConnections.push({ tool: 'MCP', purpose: 'External tool/data connections', status: 'documented', evidence: mcpFiles.join(', ') })
|
|
260
|
+
else toolConnections.push({ tool: 'MCP', purpose: 'External tool/data connections', status: 'unknown', evidence: '-' })
|
|
261
|
+
const playwrightEvidence = []
|
|
262
|
+
if (deps.playwright || deps['@playwright/test']) playwrightEvidence.push('package.json dependency')
|
|
263
|
+
if (scripts.some((item) => item.name.includes('smoke') && /browser|ui|playwright/i.test(item.command + ' ' + item.name))) playwrightEvidence.push('package.json smoke script')
|
|
264
|
+
if (configs.some((item) => item.startsWith('playwright.config'))) playwrightEvidence.push(configs.filter((item) => item.startsWith('playwright.config')).join(', '))
|
|
265
|
+
if (playwrightEvidence.length) toolConnections.push({ tool: 'Browser/Playwright', purpose: 'UI smoke and browser automation', status: 'documented', evidence: playwrightEvidence.join(', ') })
|
|
266
|
+
else toolConnections.push({ tool: 'Browser/Playwright', purpose: 'UI smoke and browser automation', status: 'unknown', evidence: '-' })
|
|
267
|
+
if (workflows.length) toolConnections.push({ tool: 'CI', purpose: 'Automated gates', status: 'documented', evidence: workflows.join(', ') })
|
|
268
|
+
else toolConnections.push({ tool: 'CI', purpose: 'Automated gates', status: 'unknown', evidence: '-' })
|
|
269
|
+
toolConnections.push({ tool: 'LSP/index', purpose: 'Symbol navigation', status: 'unknown', evidence: '-' })
|
|
270
|
+
|
|
271
|
+
const release = scripts.filter((item) => /release|deploy|publish/i.test(item.name)).map((item) => `${item.name}: ${item.command}`)
|
|
272
|
+
const smoke = scripts.filter((item) => /smoke|check|test:e2e/i.test(item.name)).map((item) => `${item.name}: ${item.command}`)
|
|
273
|
+
const externalServices = []
|
|
274
|
+
if (configs.includes('.env.example')) externalServices.push('.env.example present')
|
|
275
|
+
|
|
276
|
+
const model = {
|
|
277
|
+
target,
|
|
278
|
+
generatedAt: new Date().toISOString(),
|
|
279
|
+
identity: {
|
|
280
|
+
name: pkg?.name ?? path.basename(target),
|
|
281
|
+
repoType: inferRepoType(pkg, configs),
|
|
282
|
+
frameworks,
|
|
283
|
+
packageManager: detectPackageManager(),
|
|
284
|
+
},
|
|
285
|
+
sources: { agentRules, docs, configFiles: configs, workflows },
|
|
286
|
+
scripts,
|
|
287
|
+
formatting,
|
|
288
|
+
testing,
|
|
289
|
+
toolConnections,
|
|
290
|
+
release,
|
|
291
|
+
smoke,
|
|
292
|
+
externalServices,
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
const markdown = renderMarkdown(model)
|
|
296
|
+
|
|
297
|
+
if (write) {
|
|
298
|
+
fs.mkdirSync(path.dirname(profilePath), { recursive: true })
|
|
299
|
+
if (!force && fs.existsSync(profilePath)) {
|
|
300
|
+
console.error(`Refusing to overwrite existing ${profilePath}. Pass --force to overwrite.`)
|
|
301
|
+
process.exit(2)
|
|
302
|
+
}
|
|
303
|
+
fs.writeFileSync(profilePath, markdown, 'utf8')
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (json) console.log(JSON.stringify(model, null, 2))
|
|
307
|
+
else console.log(markdown)
|