@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.
Files changed (228) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.yml +42 -42
  2. package/.github/ISSUE_TEMPLATE/change_request.yml +50 -50
  3. package/.github/ISSUE_TEMPLATE/config.yml +5 -5
  4. package/.github/PULL_REQUEST_TEMPLATE.md +38 -38
  5. package/.github/workflows/validate-gse.yml +33 -33
  6. package/.gse/README.md +18 -18
  7. package/.gse/gse-development-protocol.md +50 -50
  8. package/.gse/project-profile.md +29 -29
  9. package/.gse/quality-gates.md +25 -25
  10. package/.gse/releases/public-registry-publication-npm.md +49 -0
  11. package/.gse/releases/public-release-owner-required.md +65 -65
  12. package/.gse/releases/public-security-contact-owner-required.md +45 -45
  13. package/.gse/state.json +147 -27
  14. package/CHANGELOG.md +31 -15
  15. package/CONTRIBUTING.md +64 -64
  16. package/LICENSE +21 -21
  17. package/README.md +14 -7
  18. package/README.zh-CN.md +14 -7
  19. package/SECURITY.md +41 -41
  20. package/SKILL.md +32 -12
  21. package/SUPPORT.md +38 -38
  22. package/assets/marketplace/README.md +7 -7
  23. package/assets/marketplace/gse-listing.json +75 -75
  24. package/assets/templates/acceptance-execution-packet.md +73 -73
  25. package/assets/templates/adr.md +14 -14
  26. package/assets/templates/change-brief.md +16 -16
  27. package/assets/templates/design.md +18 -18
  28. package/assets/templates/dispatch-packet.md +100 -92
  29. package/assets/templates/evidence.md +15 -9
  30. package/assets/templates/execution-quality-pack.md +65 -65
  31. package/assets/templates/goal-map.md +21 -21
  32. package/assets/templates/host-adapter.md +48 -48
  33. package/assets/templates/host-ui-invocation-record.md +42 -42
  34. package/assets/templates/incident-review.md +60 -60
  35. package/assets/templates/public-channel-publication-record.md +49 -49
  36. package/assets/templates/public-ci-run-record.md +53 -53
  37. package/assets/templates/public-release-record.md +65 -65
  38. package/assets/templates/public-repository-settings-record.md +59 -59
  39. package/assets/templates/public-security-contact-record.md +45 -45
  40. package/assets/templates/release-trust-record.md +32 -32
  41. package/assets/templates/review.md +18 -18
  42. package/assets/templates/role-fallback-packet.md +49 -0
  43. package/assets/templates/spec.md +16 -16
  44. package/assets/templates/target-adoption-evidence.md +29 -29
  45. package/assets/templates/tasks.md +17 -17
  46. package/assets/templates/update-release-acceptance-record.md +58 -58
  47. package/examples/README.md +22 -22
  48. package/examples/agent-runtime-host/.claude/gse-adapter.md +6 -6
  49. package/examples/agent-runtime-host/.codex/gse-adapter.md +7 -7
  50. package/examples/agent-runtime-host/.gse/goal-map.md +7 -7
  51. package/examples/agent-runtime-host/.gse/project-profile.md +27 -27
  52. package/examples/agent-runtime-host/.gse/tooling.md +5 -5
  53. package/examples/agent-runtime-host/.mcp.json +9 -9
  54. package/examples/agent-runtime-host/AGENTS.md +5 -5
  55. package/examples/agent-runtime-host/README.md +10 -10
  56. package/examples/agent-runtime-host/docs/model-routing.md +5 -5
  57. package/examples/cli-tool/.gse/project-profile.md +21 -21
  58. package/examples/cli-tool/AGENTS.md +5 -5
  59. package/examples/cli-tool/README.md +12 -12
  60. package/examples/cli-tool/package.json +21 -21
  61. package/examples/small-app/.env.example +2 -2
  62. package/examples/small-app/.github/workflows/ci.yml +8 -8
  63. package/examples/small-app/AGENTS.md +5 -5
  64. package/examples/small-app/README.md +12 -12
  65. package/examples/small-app/package.json +26 -26
  66. package/examples/small-app/playwright.config.ts +4 -4
  67. package/package.json +52 -44
  68. package/references/adoption-recipes.md +171 -171
  69. package/references/agent-roles.md +42 -21
  70. package/references/architecture-health.md +101 -101
  71. package/references/benchmark-audit.md +73 -73
  72. package/references/commands.md +74 -45
  73. package/references/community-channels.md +46 -46
  74. package/references/compatibility.md +70 -70
  75. package/references/design-basis.md +38 -38
  76. package/references/domain-model.md +129 -129
  77. package/references/domain-quality-gates.md +75 -75
  78. package/references/drift-audit.md +81 -80
  79. package/references/evidence-taxonomy.md +145 -108
  80. package/references/file-ownership.md +97 -93
  81. package/references/final-form-roadmap.md +201 -0
  82. package/references/final-readiness.md +84 -84
  83. package/references/forward-test.md +133 -133
  84. package/references/goal-map.md +36 -36
  85. package/references/host-adapters.md +129 -101
  86. package/references/learning-system.md +42 -26
  87. package/references/maintenance-cadence.md +51 -0
  88. package/references/marketplace-discovery.md +46 -46
  89. package/references/model-routing.md +103 -103
  90. package/references/open-source-defaults.md +39 -39
  91. package/references/operating-model.md +52 -52
  92. package/references/packaging.md +277 -277
  93. package/references/project-agent-workspace.md +89 -89
  94. package/references/project-bootstrap.md +122 -122
  95. package/references/project-guards.md +52 -0
  96. package/references/project-profile.md +57 -57
  97. package/references/public-release.md +174 -174
  98. package/references/quality-gates.md +96 -89
  99. package/references/recovery.md +176 -176
  100. package/references/release-trust.md +43 -43
  101. package/references/release.md +126 -126
  102. package/references/review.md +141 -141
  103. package/references/role-dispatch-fallback.md +54 -0
  104. package/references/router.md +90 -90
  105. package/references/spec-workflow.md +66 -66
  106. package/references/task-levels.md +81 -81
  107. package/references/tool-adapters.md +80 -70
  108. package/scripts/audit-acceptance-execution-packet.mjs +133 -133
  109. package/scripts/audit-adoption-recipes.mjs +99 -99
  110. package/scripts/audit-change-lifecycle.mjs +77 -77
  111. package/scripts/audit-change-system.mjs +134 -134
  112. package/scripts/audit-ci-readiness.mjs +107 -107
  113. package/scripts/audit-close-gate-hardening.mjs +188 -0
  114. package/scripts/audit-close-gate.mjs +448 -262
  115. package/scripts/audit-command-adapters.mjs +91 -91
  116. package/scripts/audit-command-execution.mjs +212 -199
  117. package/scripts/audit-commands.mjs +7 -5
  118. package/scripts/audit-compatibility.mjs +149 -149
  119. package/scripts/audit-completion-plan-drill.mjs +230 -0
  120. package/scripts/audit-completion-readiness.mjs +290 -287
  121. package/scripts/audit-continue-preflight.mjs +234 -0
  122. package/scripts/audit-distribution.mjs +251 -251
  123. package/scripts/audit-domain-quality-gates.mjs +108 -108
  124. package/scripts/audit-evidence-levels.mjs +217 -0
  125. package/scripts/audit-evidence-placeholders.mjs +126 -126
  126. package/scripts/audit-evidence-review-queue.mjs +206 -0
  127. package/scripts/audit-final-acceptance-packet.mjs +9 -9
  128. package/scripts/audit-final-form-progress-report.mjs +19 -18
  129. package/scripts/audit-final-form-roadmap.mjs +157 -0
  130. package/scripts/audit-final-form-stale-copy.mjs +2 -2
  131. package/scripts/audit-final-readiness-promotion.mjs +255 -255
  132. package/scripts/audit-final-readiness.mjs +226 -226
  133. package/scripts/audit-fixtures.mjs +154 -154
  134. package/scripts/audit-fresh-session-readiness.mjs +177 -177
  135. package/scripts/audit-host-capabilities.mjs +237 -0
  136. package/scripts/audit-host-runtime-evidence-handoff.mjs +159 -159
  137. package/scripts/audit-host-runtime-invocation-drill.mjs +240 -240
  138. package/scripts/audit-host-runtime-invocations.mjs +254 -254
  139. package/scripts/audit-host-ui-invocation.mjs +132 -132
  140. package/scripts/audit-installed-sync.mjs +203 -0
  141. package/scripts/audit-learning-drift.mjs +292 -0
  142. package/scripts/audit-learning-promotion.mjs +351 -0
  143. package/scripts/audit-learning-system.mjs +24 -14
  144. package/scripts/audit-local-final-form-completion.mjs +11 -10
  145. package/scripts/audit-maintenance-cadence.mjs +139 -0
  146. package/scripts/audit-maintenance-snapshot.mjs +181 -0
  147. package/scripts/audit-marketplace-discovery.mjs +122 -122
  148. package/scripts/audit-npm-package-metadata.mjs +160 -154
  149. package/scripts/audit-npm-publish-dry-run.mjs +194 -166
  150. package/scripts/audit-npm-tarball-install.mjs +195 -189
  151. package/scripts/audit-open-source-defaults.mjs +92 -92
  152. package/scripts/audit-open-source-readiness.mjs +97 -97
  153. package/scripts/audit-owner-external-gate-kit.mjs +12 -11
  154. package/scripts/audit-project-guards.mjs +189 -0
  155. package/scripts/audit-project.mjs +144 -141
  156. package/scripts/audit-public-acceptance-command-dry-run-drill.mjs +203 -203
  157. package/scripts/audit-public-acceptance-handoff.mjs +10 -10
  158. package/scripts/audit-public-acceptance-readiness.mjs +222 -222
  159. package/scripts/audit-public-channel-publication.mjs +248 -248
  160. package/scripts/audit-public-ci-run.mjs +184 -184
  161. package/scripts/audit-public-collaboration-templates.mjs +98 -98
  162. package/scripts/audit-public-external-gate-probe.mjs +206 -206
  163. package/scripts/audit-public-release-checklist.mjs +17 -15
  164. package/scripts/audit-public-release-decision.mjs +201 -201
  165. package/scripts/audit-public-release-metadata.mjs +176 -176
  166. package/scripts/audit-public-repository-settings.mjs +237 -237
  167. package/scripts/audit-public-security-contact.mjs +171 -171
  168. package/scripts/audit-readme-docs.mjs +6 -4
  169. package/scripts/audit-recovery-readiness.mjs +98 -98
  170. package/scripts/audit-release-bundle.mjs +13 -11
  171. package/scripts/audit-release-owner-action-plan-drill.mjs +5 -4
  172. package/scripts/audit-release-owner-action-plan.mjs +10 -10
  173. package/scripts/audit-release-readiness.mjs +106 -106
  174. package/scripts/audit-release-status-manifest.mjs +4 -4
  175. package/scripts/audit-release-trust.mjs +62 -62
  176. package/scripts/audit-remote-distribution.mjs +266 -266
  177. package/scripts/audit-roadmap-consistency.mjs +234 -230
  178. package/scripts/audit-role-dispatch-fallback.mjs +212 -0
  179. package/scripts/audit-session-sync.mjs +127 -0
  180. package/scripts/audit-signing.mjs +147 -147
  181. package/scripts/audit-state-freshness.mjs +20 -14
  182. package/scripts/audit-state-repair.mjs +360 -0
  183. package/scripts/audit-target-adoption-evidence.mjs +117 -117
  184. package/scripts/audit-target-hardening-drills.mjs +267 -0
  185. package/scripts/audit-target-project.mjs +507 -507
  186. package/scripts/audit-tool-fallback-policy.mjs +180 -0
  187. package/scripts/audit-ui-browser-evidence-policy.mjs +191 -0
  188. package/scripts/audit-update-release-acceptance.mjs +136 -136
  189. package/scripts/audit-v1-target-validation.mjs +269 -269
  190. package/scripts/audit-validation-profiles.mjs +125 -123
  191. package/scripts/backfill-evidence-levels.mjs +98 -0
  192. package/scripts/check-encoding.mjs +72 -0
  193. package/scripts/close-change.mjs +116 -116
  194. package/scripts/discover-project-profile.mjs +307 -307
  195. package/scripts/generate-command-adapter.mjs +231 -231
  196. package/scripts/generate-continue-packet.mjs +1214 -0
  197. package/scripts/generate-final-acceptance-packet.mjs +188 -173
  198. package/scripts/generate-final-form-progress-report.mjs +191 -189
  199. package/scripts/generate-host-runtime-evidence-handoff.mjs +198 -191
  200. package/scripts/generate-maintenance-snapshot.mjs +216 -0
  201. package/scripts/generate-owner-external-gate-kit.mjs +295 -295
  202. package/scripts/generate-public-acceptance-handoff.mjs +168 -156
  203. package/scripts/generate-public-release-checklist.mjs +207 -207
  204. package/scripts/generate-release-bundle.mjs +505 -505
  205. package/scripts/generate-release-owner-action-plan.mjs +172 -171
  206. package/scripts/generate-release-status-manifest.mjs +199 -198
  207. package/scripts/generate-session-prompt.mjs +188 -188
  208. package/scripts/gse.mjs +67 -67
  209. package/scripts/init-change.mjs +265 -265
  210. package/scripts/init-project.mjs +793 -712
  211. package/scripts/install-gse.mjs +234 -234
  212. package/scripts/lib/evidence-placeholders.mjs +28 -28
  213. package/scripts/package-gse.mjs +174 -174
  214. package/scripts/probe-public-external-gates.mjs +167 -167
  215. package/scripts/record-host-invocation.mjs +151 -151
  216. package/scripts/record-learning.mjs +37 -8
  217. package/scripts/record-public-channel-publication.mjs +178 -178
  218. package/scripts/record-public-ci-run.mjs +180 -180
  219. package/scripts/record-public-release.mjs +175 -175
  220. package/scripts/record-public-repository-settings.mjs +209 -209
  221. package/scripts/record-public-security-contact.mjs +157 -157
  222. package/scripts/record-session-sync.mjs +87 -0
  223. package/scripts/run-gse-command.mjs +79 -47
  224. package/scripts/run-validation-profile.mjs +24 -5
  225. package/scripts/sign-gse-package.mjs +83 -83
  226. package/scripts/update-project-state.mjs +223 -223
  227. package/scripts/validate-gse.mjs +216 -0
  228. package/scripts/verify-gse-package.mjs +85 -85
@@ -1,157 +1,157 @@
1
- #!/usr/bin/env node
2
- import fs from 'node:fs'
3
- import path from 'node:path'
4
- import { rejectPlaceholderEvidence } from './lib/evidence-placeholders.mjs'
5
-
6
- const args = process.argv.slice(2)
7
-
8
- function readArg(name, fallback = '') {
9
- const index = args.indexOf(name)
10
- if (index === -1) return fallback
11
- return args[index + 1] ?? fallback
12
- }
13
-
14
- function hasArg(name) {
15
- return args.includes(name)
16
- }
17
-
18
- const root = path.resolve(readArg('--root', path.join(import.meta.dirname, '..')))
19
- const contactStatus = readArg('--contact-status', 'pending')
20
- const contactType = readArg('--contact-type', 'unknown')
21
- const contactValue = readArg('--contact-value', '')
22
- const policyPath = readArg('--policy-path', 'SECURITY.md')
23
- const evidenceOwner = readArg('--evidence-owner', '')
24
- const evidenceDate = readArg('--evidence-date', '')
25
- const evidenceUrl = readArg('--evidence-url', '')
26
- const isPublic = readArg('--is-public', 'unknown')
27
- const policyUpdated = readArg('--security-policy-updated', 'unknown')
28
- const privateFallback = readArg('--private-fallback-channel', 'owner private coordination channel')
29
- const responseExpectation = readArg('--response-expectation', 'pending owner policy')
30
- const disclosureNotes = readArg('--disclosure-notes', 'Do not publish exploit details until the public contact is owner-accepted.')
31
- const verificationCommand = readArg('--verification-command', 'node scripts/audit-open-source-readiness.mjs --root . --json')
32
- const verificationResult = readArg('--verification-result', 'pending')
33
- const evidenceStatus = readArg('--evidence-status', contactStatus === 'accepted' ? 'accepted' : 'pending')
34
- const acceptedBy = readArg('--accepted-by', '')
35
- const acceptedAt = readArg('--accepted-at', '')
36
- const residualRisk = readArg('--residual-risk', 'Public security contact is not accepted until owner evidence is attached.')
37
- const nextAction = readArg('--next-action', 'Attach owner-approved public security contact evidence and re-run final readiness.')
38
- const out = path.resolve(readArg('--out', path.join(root, '.gse', 'releases', 'public-security-contact-owner-required.md')))
39
- const dryRun = hasArg('--dry-run')
40
- const force = hasArg('--force')
41
- const jsonOnly = hasArg('--json')
42
-
43
- const validStatuses = new Set(['pending', 'accepted'])
44
- const validContactTypes = new Set(['email', 'url', 'github-security-advisory', 'other', 'unknown'])
45
- const validTriState = new Set(['true', 'false', 'unknown'])
46
- const validEvidenceStatuses = new Set(['pending', 'accepted'])
47
- const errors = []
48
-
49
- function requireField(value, message) {
50
- if (!String(value).trim()) errors.push(message)
51
- }
52
-
53
- if (!validStatuses.has(contactStatus)) errors.push('--contact-status must be pending or accepted')
54
- if (!validContactTypes.has(contactType)) errors.push('--contact-type must be email, url, github-security-advisory, other, or unknown')
55
- if (!validTriState.has(isPublic)) errors.push('--is-public must be true, false, or unknown')
56
- if (!validTriState.has(policyUpdated)) errors.push('--security-policy-updated must be true, false, or unknown')
57
- if (!validEvidenceStatuses.has(evidenceStatus)) errors.push('--evidence-status must be pending or accepted')
58
-
59
- if (contactStatus === 'accepted') {
60
- if (contactType === 'unknown') errors.push('accepted security contact requires --contact-type')
61
- requireField(contactValue, 'accepted security contact requires --contact-value')
62
- requireField(evidenceOwner, 'accepted security contact requires --evidence-owner')
63
- requireField(evidenceDate, 'accepted security contact requires --evidence-date')
64
- requireField(evidenceUrl, 'accepted security contact requires --evidence-url')
65
- requireField(acceptedBy, 'accepted security contact requires --accepted-by')
66
- requireField(acceptedAt, 'accepted security contact requires --accepted-at')
67
- if (isPublic !== 'true') errors.push('accepted security contact requires --is-public true')
68
- if (policyUpdated !== 'true') errors.push('accepted security contact requires --security-policy-updated true')
69
- if (evidenceStatus !== 'accepted') errors.push('accepted security contact requires --evidence-status accepted')
70
- if (!dryRun) {
71
- rejectPlaceholderEvidence(errors, contactValue, '--contact-value')
72
- rejectPlaceholderEvidence(errors, evidenceOwner, '--evidence-owner')
73
- rejectPlaceholderEvidence(errors, evidenceUrl, '--evidence-url')
74
- rejectPlaceholderEvidence(errors, acceptedBy, '--accepted-by')
75
- }
76
- }
77
-
78
- const lines = [
79
- '# Public Security Contact Record',
80
- '',
81
- 'Contact status: ' + contactStatus,
82
- '',
83
- 'Contact type: ' + contactType,
84
- '',
85
- 'Contact value: ' + contactValue,
86
- '',
87
- 'Policy path: `' + policyPath + '`',
88
- '',
89
- 'Evidence owner: ' + evidenceOwner,
90
- '',
91
- 'Evidence date: ' + evidenceDate,
92
- '',
93
- 'Evidence URL or run id: ' + evidenceUrl,
94
- '',
95
- '## Public Disclosure Policy',
96
- '',
97
- '- Is this contact public? ' + isPublic,
98
- '- Security policy updated? ' + policyUpdated,
99
- '- Private fallback channel: ' + privateFallback,
100
- '- Response expectation: ' + responseExpectation,
101
- '- Embargo or disclosure notes: ' + disclosureNotes,
102
- '',
103
- '## Verification',
104
- '',
105
- 'Verification command: ' + verificationCommand,
106
- '',
107
- 'Verification result: ' + verificationResult,
108
- '',
109
- '## Acceptance',
110
- '',
111
- 'Evidence status: ' + evidenceStatus,
112
- '',
113
- 'Accepted by: ' + acceptedBy,
114
- '',
115
- 'Accepted at: ' + acceptedAt,
116
- '',
117
- '## Residual Risk',
118
- '',
119
- '- ' + residualRisk,
120
- '',
121
- '## Next Action',
122
- '',
123
- '- ' + nextAction,
124
- '',
125
- ]
126
-
127
- const report = {
128
- root,
129
- out,
130
- dryRun,
131
- contactStatus,
132
- evidenceStatus,
133
- status: errors.length ? 'failed' : dryRun ? 'ready' : 'written',
134
- errors,
135
- }
136
-
137
- if (!errors.length && !dryRun) {
138
- if (fs.existsSync(out) && !force) {
139
- report.status = 'exists'
140
- report.errors.push('output exists; use --force or choose another --out path')
141
- } else {
142
- fs.mkdirSync(path.dirname(out), { recursive: true })
143
- fs.writeFileSync(out, lines.join('\n'), 'utf8')
144
- }
145
- }
146
-
147
- if (jsonOnly) console.log(JSON.stringify(report, null, 2))
148
- else {
149
- console.log('Public security contact record status: ' + report.status)
150
- console.log('Output: ' + report.out)
151
- if (report.errors.length) {
152
- console.log('Errors:')
153
- for (const error of report.errors) console.log('- ' + error)
154
- }
155
- }
156
-
157
- if (report.status === 'failed' || report.status === 'exists') process.exit(1)
1
+ #!/usr/bin/env node
2
+ import fs from 'node:fs'
3
+ import path from 'node:path'
4
+ import { rejectPlaceholderEvidence } from './lib/evidence-placeholders.mjs'
5
+
6
+ const args = process.argv.slice(2)
7
+
8
+ function readArg(name, fallback = '') {
9
+ const index = args.indexOf(name)
10
+ if (index === -1) return fallback
11
+ return args[index + 1] ?? fallback
12
+ }
13
+
14
+ function hasArg(name) {
15
+ return args.includes(name)
16
+ }
17
+
18
+ const root = path.resolve(readArg('--root', path.join(import.meta.dirname, '..')))
19
+ const contactStatus = readArg('--contact-status', 'pending')
20
+ const contactType = readArg('--contact-type', 'unknown')
21
+ const contactValue = readArg('--contact-value', '')
22
+ const policyPath = readArg('--policy-path', 'SECURITY.md')
23
+ const evidenceOwner = readArg('--evidence-owner', '')
24
+ const evidenceDate = readArg('--evidence-date', '')
25
+ const evidenceUrl = readArg('--evidence-url', '')
26
+ const isPublic = readArg('--is-public', 'unknown')
27
+ const policyUpdated = readArg('--security-policy-updated', 'unknown')
28
+ const privateFallback = readArg('--private-fallback-channel', 'owner private coordination channel')
29
+ const responseExpectation = readArg('--response-expectation', 'pending owner policy')
30
+ const disclosureNotes = readArg('--disclosure-notes', 'Do not publish exploit details until the public contact is owner-accepted.')
31
+ const verificationCommand = readArg('--verification-command', 'node scripts/audit-open-source-readiness.mjs --root . --json')
32
+ const verificationResult = readArg('--verification-result', 'pending')
33
+ const evidenceStatus = readArg('--evidence-status', contactStatus === 'accepted' ? 'accepted' : 'pending')
34
+ const acceptedBy = readArg('--accepted-by', '')
35
+ const acceptedAt = readArg('--accepted-at', '')
36
+ const residualRisk = readArg('--residual-risk', 'Public security contact is not accepted until owner evidence is attached.')
37
+ const nextAction = readArg('--next-action', 'Attach owner-approved public security contact evidence and re-run final readiness.')
38
+ const out = path.resolve(readArg('--out', path.join(root, '.gse', 'releases', 'public-security-contact-owner-required.md')))
39
+ const dryRun = hasArg('--dry-run')
40
+ const force = hasArg('--force')
41
+ const jsonOnly = hasArg('--json')
42
+
43
+ const validStatuses = new Set(['pending', 'accepted'])
44
+ const validContactTypes = new Set(['email', 'url', 'github-security-advisory', 'other', 'unknown'])
45
+ const validTriState = new Set(['true', 'false', 'unknown'])
46
+ const validEvidenceStatuses = new Set(['pending', 'accepted'])
47
+ const errors = []
48
+
49
+ function requireField(value, message) {
50
+ if (!String(value).trim()) errors.push(message)
51
+ }
52
+
53
+ if (!validStatuses.has(contactStatus)) errors.push('--contact-status must be pending or accepted')
54
+ if (!validContactTypes.has(contactType)) errors.push('--contact-type must be email, url, github-security-advisory, other, or unknown')
55
+ if (!validTriState.has(isPublic)) errors.push('--is-public must be true, false, or unknown')
56
+ if (!validTriState.has(policyUpdated)) errors.push('--security-policy-updated must be true, false, or unknown')
57
+ if (!validEvidenceStatuses.has(evidenceStatus)) errors.push('--evidence-status must be pending or accepted')
58
+
59
+ if (contactStatus === 'accepted') {
60
+ if (contactType === 'unknown') errors.push('accepted security contact requires --contact-type')
61
+ requireField(contactValue, 'accepted security contact requires --contact-value')
62
+ requireField(evidenceOwner, 'accepted security contact requires --evidence-owner')
63
+ requireField(evidenceDate, 'accepted security contact requires --evidence-date')
64
+ requireField(evidenceUrl, 'accepted security contact requires --evidence-url')
65
+ requireField(acceptedBy, 'accepted security contact requires --accepted-by')
66
+ requireField(acceptedAt, 'accepted security contact requires --accepted-at')
67
+ if (isPublic !== 'true') errors.push('accepted security contact requires --is-public true')
68
+ if (policyUpdated !== 'true') errors.push('accepted security contact requires --security-policy-updated true')
69
+ if (evidenceStatus !== 'accepted') errors.push('accepted security contact requires --evidence-status accepted')
70
+ if (!dryRun) {
71
+ rejectPlaceholderEvidence(errors, contactValue, '--contact-value')
72
+ rejectPlaceholderEvidence(errors, evidenceOwner, '--evidence-owner')
73
+ rejectPlaceholderEvidence(errors, evidenceUrl, '--evidence-url')
74
+ rejectPlaceholderEvidence(errors, acceptedBy, '--accepted-by')
75
+ }
76
+ }
77
+
78
+ const lines = [
79
+ '# Public Security Contact Record',
80
+ '',
81
+ 'Contact status: ' + contactStatus,
82
+ '',
83
+ 'Contact type: ' + contactType,
84
+ '',
85
+ 'Contact value: ' + contactValue,
86
+ '',
87
+ 'Policy path: `' + policyPath + '`',
88
+ '',
89
+ 'Evidence owner: ' + evidenceOwner,
90
+ '',
91
+ 'Evidence date: ' + evidenceDate,
92
+ '',
93
+ 'Evidence URL or run id: ' + evidenceUrl,
94
+ '',
95
+ '## Public Disclosure Policy',
96
+ '',
97
+ '- Is this contact public? ' + isPublic,
98
+ '- Security policy updated? ' + policyUpdated,
99
+ '- Private fallback channel: ' + privateFallback,
100
+ '- Response expectation: ' + responseExpectation,
101
+ '- Embargo or disclosure notes: ' + disclosureNotes,
102
+ '',
103
+ '## Verification',
104
+ '',
105
+ 'Verification command: ' + verificationCommand,
106
+ '',
107
+ 'Verification result: ' + verificationResult,
108
+ '',
109
+ '## Acceptance',
110
+ '',
111
+ 'Evidence status: ' + evidenceStatus,
112
+ '',
113
+ 'Accepted by: ' + acceptedBy,
114
+ '',
115
+ 'Accepted at: ' + acceptedAt,
116
+ '',
117
+ '## Residual Risk',
118
+ '',
119
+ '- ' + residualRisk,
120
+ '',
121
+ '## Next Action',
122
+ '',
123
+ '- ' + nextAction,
124
+ '',
125
+ ]
126
+
127
+ const report = {
128
+ root,
129
+ out,
130
+ dryRun,
131
+ contactStatus,
132
+ evidenceStatus,
133
+ status: errors.length ? 'failed' : dryRun ? 'ready' : 'written',
134
+ errors,
135
+ }
136
+
137
+ if (!errors.length && !dryRun) {
138
+ if (fs.existsSync(out) && !force) {
139
+ report.status = 'exists'
140
+ report.errors.push('output exists; use --force or choose another --out path')
141
+ } else {
142
+ fs.mkdirSync(path.dirname(out), { recursive: true })
143
+ fs.writeFileSync(out, lines.join('\n'), 'utf8')
144
+ }
145
+ }
146
+
147
+ if (jsonOnly) console.log(JSON.stringify(report, null, 2))
148
+ else {
149
+ console.log('Public security contact record status: ' + report.status)
150
+ console.log('Output: ' + report.out)
151
+ if (report.errors.length) {
152
+ console.log('Errors:')
153
+ for (const error of report.errors) console.log('- ' + error)
154
+ }
155
+ }
156
+
157
+ if (report.status === 'failed' || report.status === 'exists') process.exit(1)
@@ -0,0 +1,87 @@
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 execute = args.includes('--execute')
15
+ const jsonOnly = args.includes('--json')
16
+ const recordPath = path.join(root, '.gse', 'session-sync.jsonl')
17
+
18
+ function requiredArg(name) {
19
+ const value = readArg(name)
20
+ if (!value) {
21
+ console.error(`${name} is required`)
22
+ process.exit(1)
23
+ }
24
+ return value
25
+ }
26
+
27
+ function normalizeStatus(value) {
28
+ return String(value || '').trim().toLowerCase()
29
+ }
30
+
31
+ const allowedStatuses = new Set([
32
+ 'sent',
33
+ 'installed-sync',
34
+ 'skipped',
35
+ 'failed',
36
+ 'archived',
37
+ 'unavailable',
38
+ ])
39
+
40
+ const status = normalizeStatus(requiredArg('--status'))
41
+ if (!allowedStatuses.has(status)) {
42
+ console.error(`--status must be one of: ${[...allowedStatuses].join(', ')}`)
43
+ process.exit(1)
44
+ }
45
+
46
+ const record = {
47
+ schemaVersion: 1,
48
+ recordedAt: new Date().toISOString(),
49
+ capability: readArg('--capability', 'gse-capability-sync'),
50
+ status,
51
+ method: requiredArg('--method'),
52
+ threadId: readArg('--thread-id', null),
53
+ project: readArg('--project', null),
54
+ workspace: readArg('--workspace', null),
55
+ evidence: requiredArg('--evidence'),
56
+ messageSummary: readArg('--message-summary', ''),
57
+ limits: [
58
+ 'This record proves a sync attempt or installed-copy parity record, not that the target session adopted the capability.',
59
+ 'A thread sync is accepted only when the transport returned success or when the failure/archived status is recorded honestly.',
60
+ ],
61
+ }
62
+
63
+ const report = {
64
+ root,
65
+ recordPath,
66
+ execute,
67
+ summary: {
68
+ status: execute ? 'written' : 'dry-run',
69
+ threadId: record.threadId,
70
+ syncStatus: record.status,
71
+ method: record.method,
72
+ },
73
+ record,
74
+ }
75
+
76
+ if (execute) {
77
+ fs.mkdirSync(path.dirname(recordPath), { recursive: true })
78
+ fs.appendFileSync(recordPath, JSON.stringify(record) + '\n', 'utf8')
79
+ }
80
+
81
+ if (jsonOnly) console.log(JSON.stringify(report, null, 2))
82
+ else {
83
+ console.log(`GSE session sync record: ${report.summary.status}`)
84
+ console.log(`Status: ${record.status}`)
85
+ console.log(`Method: ${record.method}`)
86
+ if (record.threadId) console.log(`Thread: ${record.threadId}`)
87
+ }
@@ -95,26 +95,31 @@ const commandMap = {
95
95
  effect: 'read-only',
96
96
  summary: 'Show GSE commands and project entry files.',
97
97
  },
98
- continue: {
99
- route: 'scripts/generate-session-prompt.mjs',
100
- effect: 'read-only',
101
- summary: 'Generate a continuation packet from project state.',
102
- },
103
- next: {
104
- route: 'scripts/generate-session-prompt.mjs',
105
- effect: 'read-only',
106
- summary: 'Alias for /gse continue.',
98
+ continue: {
99
+ route: 'scripts/generate-continue-packet.mjs',
100
+ effect: 'read-only',
101
+ summary: 'Run a hard continuation preflight and generate a compact state packet.',
102
+ },
103
+ next: {
104
+ route: 'scripts/generate-continue-packet.mjs',
105
+ effect: 'read-only',
106
+ summary: 'Alias for /gse continue.',
107
107
  },
108
108
  status: {
109
109
  route: 'scripts/generate-final-form-progress-report.mjs or .gse/state.json',
110
110
  effect: 'read-only',
111
111
  summary: 'Show project state, or GSE final-form progress when the target is the GSE skill.',
112
112
  },
113
- doctor: {
114
- route: 'scripts/audit-public-acceptance-readiness.mjs or scripts/audit-target-project.mjs',
115
- effect: 'read-only',
116
- summary: 'Diagnose final-form public/host acceptance blockers for GSE, or target-project GSE readiness for normal projects.',
117
- },
113
+ doctor: {
114
+ route: 'scripts/audit-public-acceptance-readiness.mjs or scripts/audit-target-project.mjs',
115
+ effect: 'read-only',
116
+ summary: 'Diagnose final-form public/host claim evidence for GSE, or target-project GSE readiness for normal projects.',
117
+ },
118
+ repair: {
119
+ route: 'scripts/audit-state-repair.mjs',
120
+ effect: 'read-only by default; reversible risk compaction with --execute',
121
+ summary: 'Diagnose or safely repair stale state, broken evidence JSONL, and overlong residual risks.',
122
+ },
118
123
  acceptance: {
119
124
  route: 'scripts/audit-public-acceptance-readiness.mjs or scripts/audit-target-project.mjs',
120
125
  effect: 'read-only',
@@ -145,11 +150,16 @@ const commandMap = {
145
150
  effect: 'read-only by default; write-with-execute for install target writes',
146
151
  summary: 'Dry-run or install GSE from a local package path or URL-shaped package source.',
147
152
  },
148
- 'public-release': {
149
- route: 'scripts/generate-public-release-checklist.mjs or scripts/audit-public-release-checklist.mjs',
150
- effect: 'read-only by default; write-with-execute for canonical checklist generation',
151
- summary: 'Dry-run or generate the ordered owner/public release checklist.',
152
- },
153
+ 'public-release': {
154
+ route: 'scripts/generate-public-release-checklist.mjs or scripts/audit-public-release-checklist.mjs',
155
+ effect: 'read-only by default; write-with-execute for canonical checklist generation',
156
+ summary: 'Dry-run or generate the ordered owner/public release checklist.',
157
+ },
158
+ maintenance: {
159
+ route: 'scripts/generate-maintenance-snapshot.mjs',
160
+ effect: 'read-only',
161
+ summary: 'Generate a recurring maintenance snapshot for benchmark, drift, evidence, installed sync, session sync, and release freshness checks.',
162
+ },
153
163
  owner: {
154
164
  route: 'scripts/audit-public-acceptance-readiness.mjs',
155
165
  effect: 'read-only',
@@ -170,11 +180,11 @@ const commandMap = {
170
180
  effect: 'read-only',
171
181
  summary: 'Select and run focused verification according to project quality gates.',
172
182
  },
173
- learn: {
174
- route: 'scripts/record-learning.mjs',
175
- effect: 'read-only by default; write-with-execute for .gse/learnings.md',
176
- summary: 'Record a reusable project lesson and skip duplicate summaries.',
177
- },
183
+ learn: {
184
+ route: 'scripts/record-learning.mjs or scripts/audit-learning-promotion.mjs',
185
+ effect: 'read-only by default; write-with-execute for .gse/learnings.md or candidate-only .gse/learning-promotions.md',
186
+ summary: 'Record a reusable project lesson, or run promotion analysis with --promote.',
187
+ },
178
188
  slice: {
179
189
  route: 'references/spec-workflow.md',
180
190
  effect: 'read-only',
@@ -207,8 +217,8 @@ if (execute && verb === 'init') {
207
217
  const changeId = rest.find((item) => !item.startsWith('--')) ?? 'gse-change'
208
218
  const level = rest.includes('--level') ? rest[rest.indexOf('--level') + 1] : 'standard'
209
219
  execution = runNode('init-change.mjs', ['--target', target, '--change-id', changeId, '--level', level, '--json'])
210
- } else if (verb === 'continue' || verb === 'next') {
211
- execution = runNode('generate-session-prompt.mjs', ['--target', target, '--json'])
220
+ } else if (verb === 'continue' || verb === 'next') {
221
+ execution = runNode('generate-continue-packet.mjs', ['--root', root, '--target', target, '--json'])
212
222
  } else if (verb === 'status') {
213
223
  const targetHasFinalFormReport = fs.existsSync(path.join(target, 'scripts', 'generate-final-form-progress-report.mjs'))
214
224
  && fs.existsSync(path.join(target, 'references', 'final-readiness.md'))
@@ -238,13 +248,19 @@ if (execute && verb === 'init') {
238
248
  }),
239
249
  stderr: state ? '' : '.gse/state.json is missing or invalid',
240
250
  }
241
- } else if (verb === 'doctor' || verb === 'acceptance') {
251
+ } else if (verb === 'doctor' || verb === 'acceptance') {
242
252
  const targetHasPublicAcceptanceDoctor = fs.existsSync(path.join(target, 'scripts', 'audit-public-acceptance-readiness.mjs'))
243
253
  && fs.existsSync(path.join(target, 'references', 'final-readiness.md'))
244
254
  execution = targetHasPublicAcceptanceDoctor
245
255
  ? runNode('audit-public-acceptance-readiness.mjs', ['--root', target, '--json'])
246
- : runNode('audit-target-project.mjs', ['--target', target, '--json'])
247
- } else if (verb === 'owner-actions' || verb === 'owner') {
256
+ : runNode('audit-target-project.mjs', ['--target', target, '--json'])
257
+ } else if (verb === 'repair') {
258
+ const repairArgs = ['--root', root, '--target', target, '--json']
259
+ if (execute) repairArgs.push('--write')
260
+ const maxRiskIndex = rest.indexOf('--max-active-risks')
261
+ if (maxRiskIndex !== -1) repairArgs.push('--max-active-risks', rest[maxRiskIndex + 1] || '6')
262
+ execution = runNode('audit-state-repair.mjs', repairArgs)
263
+ } else if (verb === 'owner-actions' || verb === 'owner') {
248
264
  const targetHasPublicAcceptanceDoctor = fs.existsSync(path.join(target, 'scripts', 'audit-public-acceptance-readiness.mjs'))
249
265
  && fs.existsSync(path.join(target, 'references', 'final-readiness.md'))
250
266
  if (targetHasPublicAcceptanceDoctor) {
@@ -445,7 +461,7 @@ if (execute && verb === 'init') {
445
461
  stderr: 'target does not expose scripts/install-gse.mjs',
446
462
  }
447
463
  }
448
- } else if (verb === 'public-release') {
464
+ } else if (verb === 'public-release') {
449
465
  const targetHasPublicReleaseChecklist = fs.existsSync(path.join(target, 'scripts', 'generate-public-release-checklist.mjs'))
450
466
  && fs.existsSync(path.join(target, 'scripts', 'audit-public-release-checklist.mjs'))
451
467
  if (targetHasPublicReleaseChecklist) {
@@ -471,9 +487,19 @@ if (execute && verb === 'init') {
471
487
  error: '/gse public-release is only available for GSE skill packages that include public release checklist scripts.',
472
488
  }),
473
489
  stderr: 'target does not expose scripts/generate-public-release-checklist.mjs and scripts/audit-public-release-checklist.mjs',
474
- }
475
- }
476
- } else if (verb === 'audit') {
490
+ }
491
+ }
492
+ } else if (verb === 'maintenance') {
493
+ const maintenanceArgs = ['--root', target, '--target', target, '--json']
494
+ const installedRootIndex = rest.indexOf('--installed-root')
495
+ if (installedRootIndex !== -1 && rest[installedRootIndex + 1]) maintenanceArgs.push('--installed-root', rest[installedRootIndex + 1])
496
+ const outIndex = rest.indexOf('--out')
497
+ if (outIndex !== -1 && rest[outIndex + 1]) maintenanceArgs.push('--out', path.resolve(rest[outIndex + 1]))
498
+ if (rest.includes('--skip-release-bundle')) maintenanceArgs.push('--skip-release-bundle')
499
+ if (rest.includes('--package-smoke')) maintenanceArgs.push('--package-smoke')
500
+ if (execute) maintenanceArgs.push('--execute')
501
+ execution = runNode('generate-maintenance-snapshot.mjs', maintenanceArgs)
502
+ } else if (verb === 'audit') {
477
503
  execution = runNode('audit-target-project.mjs', ['--target', target, '--json'])
478
504
  } else if (verb === 'close') {
479
505
  execution = runNode('audit-close-gate.mjs', ['--target', target, '--json'])
@@ -481,20 +507,26 @@ if (execute && verb === 'init') {
481
507
  const profileIndex = rest.indexOf('--profile')
482
508
  const profile = profileIndex === -1 ? 'lite' : (rest[profileIndex + 1] || 'lite')
483
509
  execution = runNode('run-validation-profile.mjs', ['--target', target, '--profile', profile, '--json'])
484
- } else if (verb === 'learn') {
485
- const learningArgs = [
486
- '--target', target,
487
- '--summary', readRestValue(rest, '--summary'),
488
- '--trigger', readRestValue(rest, '--trigger', 'reusable lesson'),
489
- '--source', readRestValue(rest, '--source', 'run-gse-command'),
490
- '--promotion', readRestValue(rest, '--promotion', 'first occurrence: learning note'),
491
- '--json',
492
- ]
493
- const impact = readRestValue(rest, '--impact')
494
- if (impact) learningArgs.push('--impact', impact)
495
- if (execute) learningArgs.push('--execute')
496
- execution = runNode('record-learning.mjs', learningArgs)
497
- }
510
+ } else if (verb === 'learn') {
511
+ if (rest.includes('--promote')) {
512
+ const promotionArgs = ['--root', root, '--target', target, '--json']
513
+ if (execute) promotionArgs.push('--write')
514
+ execution = runNode('audit-learning-promotion.mjs', promotionArgs)
515
+ } else {
516
+ const learningArgs = [
517
+ '--target', target,
518
+ '--summary', readRestValue(rest, '--summary'),
519
+ '--trigger', readRestValue(rest, '--trigger', 'reusable lesson'),
520
+ '--source', readRestValue(rest, '--source', 'run-gse-command'),
521
+ '--promotion', readRestValue(rest, '--promotion', 'first occurrence: learning note'),
522
+ '--json',
523
+ ]
524
+ const impact = readRestValue(rest, '--impact')
525
+ if (impact) learningArgs.push('--impact', impact)
526
+ if (execute) learningArgs.push('--execute')
527
+ execution = runNode('record-learning.mjs', learningArgs)
528
+ }
529
+ }
498
530
 
499
531
  const report = {
500
532
  root,
@@ -48,11 +48,30 @@ function run(script, commandArgs) {
48
48
  }
49
49
 
50
50
  function commandList(selectedProfile) {
51
- const common = [
52
- ['audit-commands.mjs', ['--root', root, '--json']],
53
- ['audit-command-execution.mjs', ['--root', root, '--profile', 'lite', '--json']],
54
- ['audit-learning-system.mjs', ['--root', root, '--json']],
55
- ]
51
+ const common = [
52
+ ['audit-commands.mjs', ['--root', root, '--json']],
53
+ ['audit-continue-preflight.mjs', ['--root', root, '--json']],
54
+ ['audit-completion-plan-drill.mjs', ['--root', root, '--json']],
55
+ ['audit-project-guards.mjs', ['--root', root, '--json']],
56
+ ['backfill-evidence-levels.mjs', ['--root', target, '--json']],
57
+ ['audit-evidence-levels.mjs', ['--root', root, '--target', target, '--json']],
58
+ ['audit-evidence-review-queue.mjs', ['--root', root, '--target', target, '--json']],
59
+ ['audit-ui-browser-evidence-policy.mjs', ['--root', root, '--target', target, '--json']],
60
+ ['audit-role-dispatch-fallback.mjs', ['--root', root, '--target', target, '--json']],
61
+ ['audit-close-gate-hardening.mjs', ['--root', root, '--json']],
62
+ ['audit-state-repair.mjs', ['--root', root, '--target', target, '--json']],
63
+ ['audit-learning-promotion.mjs', ['--root', root, '--target', target, '--json']],
64
+ ['audit-learning-drift.mjs', ['--root', root, '--target', target, '--json']],
65
+ ['audit-host-capabilities.mjs', ['--root', root, '--target', target, '--json']],
66
+ ['audit-tool-fallback-policy.mjs', ['--root', root, '--target', target, '--json']],
67
+ ['audit-target-hardening-drills.mjs', ['--root', root, '--json']],
68
+ ['audit-maintenance-cadence.mjs', ['--root', root, '--json']],
69
+ ['audit-maintenance-snapshot.mjs', ['--root', root, '--json']],
70
+ ['audit-installed-sync.mjs', ['--root', root, '--json']],
71
+ ['audit-session-sync.mjs', ['--root', root, '--json']],
72
+ ['audit-command-execution.mjs', ['--root', root, '--profile', 'lite', '--json']],
73
+ ['audit-learning-system.mjs', ['--root', root, '--json']],
74
+ ]
56
75
 
57
76
  const targetChecks = target === root
58
77
  ? []