@knights-eye-chess/ai-analysis 0.0.0-stage → 0.1.0-dev.14
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/LICENSE +235 -0
- package/LICENSING.md +26 -0
- package/NOTICE +5 -0
- package/NPM-PUBLISHING.md +24 -0
- package/README.md +141 -2
- package/SOURCE-ORIGIN.json +16 -0
- package/THIRD_PARTY_NOTICES.md +18 -0
- package/build.mjs +22 -0
- package/dist/answer-pipeline.test.mjs +375 -0
- package/dist/chunk-PLKNJRPF.js +10662 -0
- package/dist/chunk-XQDZJOYD.js +2515 -0
- package/dist/index.js +146 -0
- package/dist/owner-tests/chess-reasoning-compact-search-preparation.test.mjs +963 -0
- package/dist/owner-tests/mechanism-encoding.test.mjs +529 -0
- package/dist/owner-tests/move-mechanism-facts.test.mjs +396 -0
- package/dist/owner-tests/pipeline-host-preparation.test.mjs +10556 -0
- package/dist/owner-tests/position-preparation.test.mjs +625 -0
- package/dist/owner-tests/preparation-consolidation.test.mjs +1052 -0
- package/dist/owner-tests/prose-reference-admission.test.mjs +1770 -0
- package/dist/owner-tests/score-comparison-notices.test.mjs +240 -0
- package/dist/owner-tests/simple-engine-presentation.test.mjs +233 -0
- package/dist/owner-tests/tool-input-loop-guard.test.mjs +78 -0
- package/dist/research.js +2274 -0
- package/dist/runtime-closure.json +103 -0
- package/dist/shared-runtime-closure.json +39 -0
- package/dist/shared.js +152 -0
- package/dist/types/ai-request-failure.d.ts +14 -0
- package/dist/types/ai-request-limits.d.ts +4 -0
- package/dist/types/ai-routing-diagnostics.d.ts +14 -0
- package/dist/types/chess-reasoning/ablation-adaptive-evidence-loop.d.ts +127 -0
- package/dist/types/chess-reasoning/ablation-adaptive-runtime.d.ts +178 -0
- package/dist/types/chess-reasoning/ablation-direct-synthesis.d.ts +1030 -0
- package/dist/types/chess-reasoning/ablation-evidence-bundle.d.ts +185 -0
- package/dist/types/chess-reasoning/ablation-evidence-capture.d.ts +37 -0
- package/dist/types/chess-reasoning/ablation-lean-direct-runtime.d.ts +193 -0
- package/dist/types/chess-reasoning/ablation-model-facing-evidence.d.ts +38 -0
- package/dist/types/chess-reasoning/ablation-transport-correction.d.ts +13 -0
- package/dist/types/chess-reasoning/ai-sdk-runtime-support.d.ts +93 -0
- package/dist/types/chess-reasoning/answer-host-contracts.d.ts +59 -0
- package/dist/types/chess-reasoning/answer-model-connector.d.ts +68 -0
- package/dist/types/chess-reasoning/answer-pipeline-exports.d.ts +98 -0
- package/dist/types/chess-reasoning/answer-pipeline.d.ts +41 -0
- package/dist/types/chess-reasoning/answer-reference-validation.d.ts +40 -0
- package/dist/types/chess-reasoning/answer-tool-host.d.ts +8 -0
- package/dist/types/chess-reasoning/branch-expansion-policy.d.ts +13 -0
- package/dist/types/chess-reasoning/branch-expansion.d.ts +39 -0
- package/dist/types/chess-reasoning/causal-claim-checks.d.ts +21 -0
- package/dist/types/chess-reasoning/chess-reference-dictionary.d.ts +13 -0
- package/dist/types/chess-reasoning/classification-question-target.d.ts +22 -0
- package/dist/types/chess-reasoning/classification-reassessment.d.ts +31 -0
- package/dist/types/chess-reasoning/compact-search-preparation.d.ts +7 -0
- package/dist/types/chess-reasoning/concept-registry.d.ts +99 -0
- package/dist/types/chess-reasoning/conversation-context.d.ts +12 -0
- package/dist/types/chess-reasoning/engine-search-failure.d.ts +7 -0
- package/dist/types/chess-reasoning/evidence-citation-normalization.d.ts +9 -0
- package/dist/types/chess-reasoning/evidence-licenses.d.ts +57 -0
- package/dist/types/chess-reasoning/evidence-selector-contract.d.ts +5 -0
- package/dist/types/chess-reasoning/existing-analysis-context.d.ts +104 -0
- package/dist/types/chess-reasoning/fact-observation-provider.d.ts +15 -0
- package/dist/types/chess-reasoning/fact-provider.d.ts +111 -0
- package/dist/types/chess-reasoning/fresh-engine-pv-witnesses.d.ts +67 -0
- package/dist/types/chess-reasoning/historical-prose.d.ts +23 -0
- package/dist/types/chess-reasoning/idea-graph.d.ts +34 -0
- package/dist/types/chess-reasoning/initial-search-plan.d.ts +37 -0
- package/dist/types/chess-reasoning/lossless-evidence-sharing.d.ts +18 -0
- package/dist/types/chess-reasoning/matched-comparison.d.ts +10 -0
- package/dist/types/chess-reasoning/material-accounting.d.ts +80 -0
- package/dist/types/chess-reasoning/material-format.d.ts +4 -0
- package/dist/types/chess-reasoning/mechanical-fact-provider.d.ts +33 -0
- package/dist/types/chess-reasoning/mechanical-ray-facts.d.ts +19 -0
- package/dist/types/chess-reasoning/mechanism-presentation.d.ts +9 -0
- package/dist/types/chess-reasoning/move-mechanism-facts.d.ts +45 -0
- package/dist/types/chess-reasoning/native-answer-connector.d.ts +4 -0
- package/dist/types/chess-reasoning/opening-source-contracts.d.ts +54 -0
- package/dist/types/chess-reasoning/opening-source-credits.d.ts +16 -0
- package/dist/types/chess-reasoning/opponent-threat-preparation.d.ts +7 -0
- package/dist/types/chess-reasoning/piece-identities.d.ts +11 -0
- package/dist/types/chess-reasoning/poc-contracts.d.ts +1026 -0
- package/dist/types/chess-reasoning/poc-hypotheses.d.ts +74 -0
- package/dist/types/chess-reasoning/poc-move-witnesses.d.ts +13 -0
- package/dist/types/chess-reasoning/poc-observations.d.ts +23 -0
- package/dist/types/chess-reasoning/poc-piece-refs.d.ts +12 -0
- package/dist/types/chess-reasoning/poc-plan-model.d.ts +45 -0
- package/dist/types/chess-reasoning/poc-semantic-text.d.ts +8 -0
- package/dist/types/chess-reasoning/poc-tools.d.ts +81 -0
- package/dist/types/chess-reasoning/portable-answer-runtime.d.ts +291 -0
- package/dist/types/chess-reasoning/position-analysis-contracts.d.ts +31 -0
- package/dist/types/chess-reasoning/position-analysis-scope.d.ts +3 -0
- package/dist/types/chess-reasoning/preparation-consolidation.d.ts +21 -0
- package/dist/types/chess-reasoning/production-observation-provider.d.ts +16 -0
- package/dist/types/chess-reasoning/question-routing.d.ts +326 -0
- package/dist/types/chess-reasoning/recorded-main-line.d.ts +37 -0
- package/dist/types/chess-reasoning/recorded-position-tools.d.ts +11 -0
- package/dist/types/chess-reasoning/recorded-reference-context.d.ts +13 -0
- package/dist/types/chess-reasoning/recorded-selected-classification.d.ts +36 -0
- package/dist/types/chess-reasoning/reference-limits.d.ts +2 -0
- package/dist/types/chess-reasoning/research-exports.d.ts +197 -0
- package/dist/types/chess-reasoning/saved-score-presentation.d.ts +14 -0
- package/dist/types/chess-reasoning/score-comparison-notices.d.ts +33 -0
- package/dist/types/chess-reasoning/server-simple-policy.d.ts +31 -0
- package/dist/types/chess-reasoning/simple-agent-config.d.ts +73 -0
- package/dist/types/chess-reasoning/simple-board-analysis.d.ts +85 -0
- package/dist/types/chess-reasoning/simple-compact-evidence.d.ts +7 -0
- package/dist/types/chess-reasoning/simple-completion.d.ts +23 -0
- package/dist/types/chess-reasoning/simple-engine-presentation.d.ts +3 -0
- package/dist/types/chess-reasoning/simple-evidence-preparation.d.ts +17 -0
- package/dist/types/chess-reasoning/simple-evidence-view.d.ts +17 -0
- package/dist/types/chess-reasoning/simple-explanation-coverage.d.ts +90 -0
- package/dist/types/chess-reasoning/simple-fact-delivery.d.ts +43 -0
- package/dist/types/chess-reasoning/simple-fallback-premise.d.ts +5 -0
- package/dist/types/chess-reasoning/simple-prose-references.d.ts +108 -0
- package/dist/types/chess-reasoning/simple-runtime-version.d.ts +1 -0
- package/dist/types/chess-reasoning/stable.d.ts +2 -0
- package/dist/types/chess-reasoning/tool-input-loop-guard.d.ts +5 -0
- package/dist/types/chess-reasoning/types.d.ts +180 -0
- package/dist/types/chess-reasoning/visible-support-lines.d.ts +12 -0
- package/dist/types/chess-reasoning/wikibooks-index.d.ts +30 -0
- package/dist/types/chess-reasoning/wikibooks-tool-context.d.ts +10 -0
- package/dist/types/player-perspective.d.ts +16 -0
- package/dist/types/shared-exports.d.ts +22 -0
- package/docs/API.md +82 -0
- package/docs/OWNERSHIP-ADOPTION.md +35 -0
- package/docs/OWNERSHIP-DRIFT.json +55 -0
- package/docs/RESEARCH-API.md +28 -0
- package/licenses/third-party/INVENTORY.json +202 -0
- package/licenses/third-party/ai-7.0.85/LICENSE +13 -0
- package/licenses/third-party/ai-sdk--gateway-4.0.69/LICENSE +13 -0
- package/licenses/third-party/ai-sdk--provider-4.0.9/LICENSE +13 -0
- package/licenses/third-party/ai-sdk--provider-utils-5.0.34/APACHE-2.0.txt +73 -0
- package/licenses/third-party/ai-sdk--provider-utils-5.0.34/src/to-json-schema/zod3-to-json-schema/LICENSE +16 -0
- package/licenses/third-party/chess.js-1.4.0/LICENSE +23 -0
- package/licenses/third-party/eventsource-parser-3.1.1/LICENSE +21 -0
- package/licenses/third-party/json-schema-0.4.0/LICENSE +195 -0
- package/licenses/third-party/standard-schema--spec-1.1.0/LICENSE +21 -0
- package/licenses/third-party/types--json-schema-7.0.15/LICENSE +21 -0
- package/licenses/third-party/types--node-22.19.19/LICENSE +21 -0
- package/licenses/third-party/undici-7.30.0/LICENSE +21 -0
- package/licenses/third-party/undici-7.30.0/lib/web/fetch/LICENSE +21 -0
- package/licenses/third-party/undici-types-6.21.0/LICENSE +21 -0
- package/licenses/third-party/vercel--oidc-3.2.0/LICENSE +202 -0
- package/licenses/third-party/workflow--serde-4.1.0/APACHE-2.0.txt +73 -0
- package/licenses/third-party/workflow--serde-4.1.0/LICENSE.md +3 -0
- package/licenses/third-party/zod-4.6.5/LICENSE +21 -0
- package/npm-release.json +5 -0
- package/package.json +72 -4
- package/scripts/check-release-tooling.mjs +22 -0
- package/scripts/pack.mjs +68 -0
- package/scripts/publish-reviewed.mjs +72 -0
- package/scripts/release-tooling.json +13 -0
- package/scripts/update-dependency.mjs +44 -0
- package/scripts/verify-release.mjs +52 -0
- package/src/ai-request-failure.ts +34 -0
- package/src/ai-request-limits.ts +4 -0
- package/src/ai-routing-diagnostics.ts +33 -0
- package/src/chess-reasoning/ablation-adaptive-evidence-loop.ts +515 -0
- package/src/chess-reasoning/ablation-adaptive-runtime.ts +924 -0
- package/src/chess-reasoning/ablation-direct-synthesis.ts +1128 -0
- package/src/chess-reasoning/ablation-evidence-bundle.ts +726 -0
- package/src/chess-reasoning/ablation-evidence-capture.ts +513 -0
- package/src/chess-reasoning/ablation-lean-direct-runtime.ts +670 -0
- package/src/chess-reasoning/ablation-model-facing-evidence.ts +212 -0
- package/src/chess-reasoning/ablation-transport-correction.ts +106 -0
- package/src/chess-reasoning/ai-sdk-runtime-support.ts +381 -0
- package/src/chess-reasoning/answer-host-contracts.ts +10 -0
- package/src/chess-reasoning/answer-model-connector.ts +83 -0
- package/src/chess-reasoning/answer-pipeline-exports.ts +98 -0
- package/src/chess-reasoning/answer-pipeline.ts +195 -0
- package/src/chess-reasoning/answer-reference-validation.ts +124 -0
- package/src/chess-reasoning/answer-tool-host.ts +10 -0
- package/src/chess-reasoning/branch-expansion-policy.ts +32 -0
- package/src/chess-reasoning/branch-expansion.ts +80 -0
- package/src/chess-reasoning/causal-claim-checks.ts +256 -0
- package/src/chess-reasoning/chess-reference-dictionary.ts +21 -0
- package/src/chess-reasoning/classification-question-target.ts +30 -0
- package/src/chess-reasoning/classification-reassessment.ts +34 -0
- package/src/chess-reasoning/compact-search-preparation.ts +125 -0
- package/src/chess-reasoning/concept-registry.ts +275 -0
- package/src/chess-reasoning/conversation-context.ts +29 -0
- package/src/chess-reasoning/engine-search-failure.ts +11 -0
- package/src/chess-reasoning/evidence-citation-normalization.ts +15 -0
- package/src/chess-reasoning/evidence-licenses.ts +166 -0
- package/src/chess-reasoning/evidence-selector-contract.ts +5 -0
- package/src/chess-reasoning/existing-analysis-context.ts +544 -0
- package/src/chess-reasoning/fact-observation-provider.ts +134 -0
- package/src/chess-reasoning/fact-provider.ts +250 -0
- package/src/chess-reasoning/fresh-engine-pv-witnesses.ts +128 -0
- package/src/chess-reasoning/historical-prose.ts +116 -0
- package/src/chess-reasoning/idea-graph.ts +224 -0
- package/src/chess-reasoning/initial-search-plan.ts +115 -0
- package/src/chess-reasoning/lossless-evidence-sharing.ts +135 -0
- package/src/chess-reasoning/matched-comparison.ts +40 -0
- package/src/chess-reasoning/material-accounting.ts +55 -0
- package/src/chess-reasoning/material-format.ts +47 -0
- package/src/chess-reasoning/mechanical-fact-provider.ts +1602 -0
- package/src/chess-reasoning/mechanical-ray-facts.ts +123 -0
- package/src/chess-reasoning/mechanism-presentation.ts +94 -0
- package/src/chess-reasoning/move-mechanism-facts.ts +185 -0
- package/src/chess-reasoning/native-answer-connector.ts +13 -0
- package/src/chess-reasoning/opening-source-contracts.ts +47 -0
- package/src/chess-reasoning/opening-source-credits.ts +53 -0
- package/src/chess-reasoning/opponent-threat-preparation.ts +98 -0
- package/src/chess-reasoning/piece-identities.ts +159 -0
- package/src/chess-reasoning/poc-contracts.ts +1097 -0
- package/src/chess-reasoning/poc-hypotheses.ts +759 -0
- package/src/chess-reasoning/poc-move-witnesses.ts +170 -0
- package/src/chess-reasoning/poc-observations.ts +611 -0
- package/src/chess-reasoning/poc-piece-refs.ts +62 -0
- package/src/chess-reasoning/poc-plan-model.ts +345 -0
- package/src/chess-reasoning/poc-semantic-text.ts +10 -0
- package/src/chess-reasoning/poc-tools.ts +978 -0
- package/src/chess-reasoning/portable-answer-runtime.ts +684 -0
- package/src/chess-reasoning/position-analysis-contracts.ts +88 -0
- package/src/chess-reasoning/position-analysis-scope.ts +20 -0
- package/src/chess-reasoning/preparation-consolidation.ts +91 -0
- package/src/chess-reasoning/production-observation-provider.ts +41 -0
- package/src/chess-reasoning/question-routing.ts +332 -0
- package/src/chess-reasoning/recorded-main-line.ts +55 -0
- package/src/chess-reasoning/recorded-position-tools.ts +78 -0
- package/src/chess-reasoning/recorded-reference-context.ts +44 -0
- package/src/chess-reasoning/recorded-selected-classification.ts +54 -0
- package/src/chess-reasoning/reference-limits.ts +2 -0
- package/src/chess-reasoning/research-exports.ts +197 -0
- package/src/chess-reasoning/saved-score-presentation.ts +6 -0
- package/src/chess-reasoning/score-comparison-notices.ts +115 -0
- package/src/chess-reasoning/server-simple-policy.ts +75 -0
- package/src/chess-reasoning/simple-agent-config.ts +58 -0
- package/src/chess-reasoning/simple-board-analysis.ts +57 -0
- package/src/chess-reasoning/simple-compact-evidence.ts +79 -0
- package/src/chess-reasoning/simple-completion.ts +37 -0
- package/src/chess-reasoning/simple-engine-presentation.ts +95 -0
- package/src/chess-reasoning/simple-evidence-preparation.ts +32 -0
- package/src/chess-reasoning/simple-evidence-view.ts +69 -0
- package/src/chess-reasoning/simple-explanation-coverage.ts +118 -0
- package/src/chess-reasoning/simple-fact-delivery.ts +52 -0
- package/src/chess-reasoning/simple-fallback-premise.ts +65 -0
- package/src/chess-reasoning/simple-prose-references.ts +528 -0
- package/src/chess-reasoning/simple-runtime-version.ts +2 -0
- package/src/chess-reasoning/stable.ts +18 -0
- package/src/chess-reasoning/tool-input-loop-guard.ts +38 -0
- package/src/chess-reasoning/types.ts +195 -0
- package/src/chess-reasoning/visible-support-lines.ts +44 -0
- package/src/chess-reasoning/wikibooks-index.ts +56 -0
- package/src/chess-reasoning/wikibooks-tool-context.ts +91 -0
- package/src/player-perspective.ts +41 -0
- package/src/shared-exports.ts +23 -0
- package/test/answer-pipeline.test.mjs +375 -0
- package/test/owner/chess-reasoning-compact-search-preparation.test.mjs +111 -0
- package/test/owner/mechanism-encoding.test.mjs +78 -0
- package/test/owner/move-mechanism-facts.test.mjs +105 -0
- package/test/owner/pipeline-host-preparation.test.mjs +115 -0
- package/test/owner/position-preparation.test.mjs +22 -0
- package/test/owner/preparation-consolidation.test.mjs +74 -0
- package/test/owner/prose-reference-admission.test.mjs +26 -0
- package/test/owner/score-comparison-notices.test.mjs +116 -0
- package/test/owner/simple-engine-presentation.test.mjs +50 -0
- package/test/owner/tool-input-loop-guard.test.mjs +25 -0
- package/test-types.mts +23 -0
- package/tsconfig.json +22 -0
package/package.json
CHANGED
|
@@ -1,6 +1,74 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knights-eye-chess/ai-analysis",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.0-dev.14",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"files": [
|
|
6
|
+
"dist",
|
|
7
|
+
"src",
|
|
8
|
+
"build.mjs",
|
|
9
|
+
"tsconfig.json",
|
|
10
|
+
"README.md",
|
|
11
|
+
"test-types.mts",
|
|
12
|
+
"test",
|
|
13
|
+
"SOURCE-ORIGIN.json",
|
|
14
|
+
"scripts",
|
|
15
|
+
"LICENSE",
|
|
16
|
+
"NOTICE",
|
|
17
|
+
"LICENSING.md",
|
|
18
|
+
"THIRD_PARTY_NOTICES.md",
|
|
19
|
+
"licenses",
|
|
20
|
+
"NPM-PUBLISHING.md",
|
|
21
|
+
"npm-release.json",
|
|
22
|
+
"docs"
|
|
23
|
+
],
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./dist/types/chess-reasoning/answer-pipeline-exports.d.ts",
|
|
27
|
+
"import": "./dist/index.js"
|
|
28
|
+
},
|
|
29
|
+
"./research": {
|
|
30
|
+
"types": "./dist/types/chess-reasoning/research-exports.d.ts",
|
|
31
|
+
"import": "./dist/research.js"
|
|
32
|
+
},
|
|
33
|
+
"./shared": {
|
|
34
|
+
"types": "./dist/types/shared-exports.d.ts",
|
|
35
|
+
"import": "./dist/shared.js"
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "node build.mjs",
|
|
40
|
+
"test": "node --test dist/answer-pipeline.test.mjs dist/owner-tests/*.test.mjs",
|
|
41
|
+
"test:types": "tsc --noEmit --strict --target ES2022 --module NodeNext --moduleResolution NodeNext --lib ES2022,DOM,DOM.Iterable test-types.mts",
|
|
42
|
+
"check": "npm run build && npm test && npm run test:types",
|
|
43
|
+
"pack:checked": "npm run check && node scripts/pack.mjs",
|
|
44
|
+
"pack:artifact": "node scripts/pack.mjs",
|
|
45
|
+
"publish:verify": "node scripts/verify-release.mjs",
|
|
46
|
+
"publish:prepare": "npm run pack:checked && npm run publish:verify"
|
|
47
|
+
},
|
|
48
|
+
"engines": {
|
|
49
|
+
"node": ">=24.0.0"
|
|
50
|
+
},
|
|
51
|
+
"dependencies": {
|
|
52
|
+
"@ai-sdk/provider": "4.0.9",
|
|
53
|
+
"@ai-sdk/provider-utils": "5.0.34",
|
|
54
|
+
"@knights-eye-chess/move-classifier": "0.1.0-dev.10",
|
|
55
|
+
"@types/json-schema": "7.0.15",
|
|
56
|
+
"@types/node": "22.19.19",
|
|
57
|
+
"ai": "7.0.85",
|
|
58
|
+
"chess.js": "1.4.0"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"esbuild": "0.28.0",
|
|
62
|
+
"typescript": "5.9.3"
|
|
63
|
+
},
|
|
64
|
+
"repository": {
|
|
65
|
+
"type": "git",
|
|
66
|
+
"url": "git+https://github.com/knights-eye-chess/ai-analysis.git"
|
|
67
|
+
},
|
|
68
|
+
"license": "AGPL-3.0-or-later",
|
|
69
|
+
"publishConfig": {
|
|
70
|
+
"registry": "https://registry.npmjs.org/",
|
|
71
|
+
"access": "public",
|
|
72
|
+
"tag": "next"
|
|
73
|
+
}
|
|
74
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Generated from knightseye-net/tools/release-tooling; edit the canonical template and sync.
|
|
2
|
+
import { readFileSync } from 'node:fs';
|
|
3
|
+
import { createHash } from 'node:crypto';
|
|
4
|
+
import { fileURLToPath } from 'node:url';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
|
|
7
|
+
export function assertReleaseTooling(root = fileURLToPath(new URL('../', import.meta.url))) {
|
|
8
|
+
const manifest = JSON.parse(readFileSync(path.join(root, 'scripts/release-tooling.json'), 'utf8'));
|
|
9
|
+
if (manifest.schema !== 1 || manifest.canonical !== 'knightseye-net/tools/release-tooling') throw Error('Invalid release tooling stamp');
|
|
10
|
+
const required = ['scripts/pack.mjs', 'scripts/publish-reviewed.mjs', '.github/workflows/npm-publish.yml', 'scripts/verify-release.mjs', 'scripts/update-dependency.mjs', 'scripts/check-release-tooling.mjs', '.github/workflows/quality.yml'];
|
|
11
|
+
if (!manifest.sha256 || required.some(relative => !/^[a-f0-9]{64}$/.test(manifest.sha256[relative] || ''))) throw Error('Incomplete release tooling stamp');
|
|
12
|
+
for (const [relative, expected] of Object.entries(manifest.sha256)) {
|
|
13
|
+
if (path.isAbsolute(relative) || relative.split('/').includes('..')) throw Error(`Invalid tooling path: ${relative}`);
|
|
14
|
+
const actual = createHash('sha256').update(readFileSync(path.join(root, relative))).digest('hex');
|
|
15
|
+
if (actual !== expected) throw Error(`Release tooling drift: ${relative}. Sync from ${manifest.canonical} before releasing.`);
|
|
16
|
+
}
|
|
17
|
+
return manifest;
|
|
18
|
+
}
|
|
19
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
20
|
+
assertReleaseTooling();
|
|
21
|
+
console.log('Release tooling stamp verified');
|
|
22
|
+
}
|
package/scripts/pack.mjs
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// Generated from knightseye-net/tools/release-tooling; edit the canonical template and sync.
|
|
2
|
+
import { assertReleaseTooling } from './check-release-tooling.mjs';
|
|
3
|
+
assertReleaseTooling();
|
|
4
|
+
import { readFileSync, writeFileSync, mkdtempSync, mkdirSync, copyFileSync, existsSync, rmSync, chmodSync, statSync } from 'node:fs';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
import path from 'node:path';
|
|
7
|
+
import os from 'node:os';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
|
|
10
|
+
const root = fileURLToPath(new URL('../', import.meta.url));
|
|
11
|
+
const destination = path.resolve(process.argv[2] || path.join(root, 'artifacts'));
|
|
12
|
+
const release = JSON.parse(readFileSync(path.join(root, 'npm-release.json'), 'utf8'));
|
|
13
|
+
function run(command, args, cwd = root) {
|
|
14
|
+
const result = spawnSync(command, args, { cwd, encoding: 'utf8' });
|
|
15
|
+
if (result.status !== 0) throw Error(result.stderr || result.stdout || `${command} failed`);
|
|
16
|
+
return result.stdout;
|
|
17
|
+
}
|
|
18
|
+
const listing = JSON.parse(run('npm', ['pack', '--dry-run', '--json', '--ignore-scripts']))[0];
|
|
19
|
+
const stage = mkdtempSync(path.join(os.tmpdir(), 'knights-eye-pack-'));
|
|
20
|
+
const output = mkdtempSync(path.join(os.tmpdir(), 'knights-eye-archive-'));
|
|
21
|
+
try {
|
|
22
|
+
for (const { path: relative } of listing.files) {
|
|
23
|
+
if (relative === 'npm-shrinkwrap.json' || relative === 'package-lock.json' || relative.startsWith('vendor/')) continue;
|
|
24
|
+
const to = path.join(stage, relative);
|
|
25
|
+
mkdirSync(path.dirname(to), { recursive: true });
|
|
26
|
+
const source = path.join(root, relative);
|
|
27
|
+
copyFileSync(source, to);
|
|
28
|
+
chmodSync(to, statSync(source).mode & 0o111 ? 0o755 : 0o644);
|
|
29
|
+
}
|
|
30
|
+
const pkg = JSON.parse(readFileSync(path.join(stage, 'package.json'), 'utf8'));
|
|
31
|
+
const dependencies = pkg.dependencies || {};
|
|
32
|
+
const mapping = release.registryDependencies || {};
|
|
33
|
+
for (const [name, version] of Object.entries(mapping)) {
|
|
34
|
+
if (!/^\d+\.\d+\.\d+(?:-[\w.-]+)?$/.test(version)) throw Error(`Missing exact registry release version: ${name}`);
|
|
35
|
+
const value = dependencies[name];
|
|
36
|
+
if (!value) throw Error(`Unexpected registry release dependency: ${name}`);
|
|
37
|
+
if (value.startsWith('file:')) {
|
|
38
|
+
const original = JSON.parse(run('tar', ['-xOf', path.resolve(root, value.slice(5)), 'package/package.json']));
|
|
39
|
+
if (original.name !== name) throw Error(`Dependency identity mismatch: ${name}`);
|
|
40
|
+
} else if (value !== version) throw Error(`Registry dependency must match exact release version: ${name}`);
|
|
41
|
+
dependencies[name] = version;
|
|
42
|
+
}
|
|
43
|
+
for (const [name, value] of Object.entries(dependencies)) {
|
|
44
|
+
if (value.startsWith('file:') || (name.startsWith('@knights-eye-chess/') && !mapping[name])) throw Error(`Missing exact registry release version: ${name}`);
|
|
45
|
+
}
|
|
46
|
+
delete pkg.private;
|
|
47
|
+
delete pkg.overrides;
|
|
48
|
+
pkg.publishConfig = { registry: 'https://registry.npmjs.org/', access: 'public', tag: 'next' };
|
|
49
|
+
writeFileSync(path.join(stage, 'package.json'), JSON.stringify(pkg, null, 2) + '\n');
|
|
50
|
+
chmodSync(path.join(stage, 'package.json'), 0o644);
|
|
51
|
+
const bins = typeof pkg.bin === 'string' ? [pkg.bin] : Object.values(pkg.bin || {});
|
|
52
|
+
for (const entry of bins) {
|
|
53
|
+
const target = path.resolve(stage, entry);
|
|
54
|
+
if (!target.startsWith(stage + path.sep)) throw Error(`Invalid binary target: ${entry}`);
|
|
55
|
+
chmodSync(target, 0o755);
|
|
56
|
+
}
|
|
57
|
+
const packed = JSON.parse(run('npm', ['pack', '--ignore-scripts', '--json', '--pack-destination', output], stage))[0];
|
|
58
|
+
const bytes = readFileSync(path.join(output, packed.filename));
|
|
59
|
+
mkdirSync(destination, { recursive: true });
|
|
60
|
+
const target = path.join(destination, packed.filename);
|
|
61
|
+
if (existsSync(target)) {
|
|
62
|
+
if (!readFileSync(target).equals(bytes)) throw Error(`Archive is immutable: ${target}. Bump the version before changing its contents.`);
|
|
63
|
+
} else writeFileSync(target, bytes, { flag: 'wx' });
|
|
64
|
+
console.log(JSON.stringify({ ...packed, archive: target, sourcePrivate: true, registryDependencies: pkg.dependencies || {} }, null, 2));
|
|
65
|
+
} finally {
|
|
66
|
+
rmSync(stage, { recursive: true, force: true });
|
|
67
|
+
rmSync(output, { recursive: true, force: true });
|
|
68
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// Generated from knightseye-net/tools/release-tooling; edit the canonical template and sync.
|
|
2
|
+
import { assertReleaseTooling } from './check-release-tooling.mjs';
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
import { createHash } from 'node:crypto';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
|
|
9
|
+
export function npmFailure(result) {
|
|
10
|
+
let error;
|
|
11
|
+
for (const output of [result.stdout, result.stderr]) {
|
|
12
|
+
try { const parsed = JSON.parse(output || '{}'); error ||= parsed.error; } catch {}
|
|
13
|
+
}
|
|
14
|
+
const allowed = new Set(['EOTP', 'E401', 'E403', 'E404', 'E409', 'E422', 'E429', 'E500', 'E502', 'E503', 'E504', 'EPROVENANCE', 'EUSAGE', 'ENEEDAUTH', 'ENOTP', 'EPRIVATE', 'EPUBLISHCONFLICT', 'EUNSCOPED', 'ECONNRESET', 'ETIMEDOUT', 'ENOTFOUND']);
|
|
15
|
+
const candidate = typeof error?.code === 'string' ? error.code : (result.stderr || '').match(/^npm (?:error|ERR!) code ([A-Z][A-Z0-9]+)\s*$/m)?.[1];
|
|
16
|
+
const code = allowed.has(candidate) ? candidate : 'UNKNOWN';
|
|
17
|
+
const rawStatus = error?.statusCode ?? error?.status ?? (/^E[45]\d\d$/.test(code) ? Number(code.slice(1)) : undefined);
|
|
18
|
+
const httpStatus = Number.isInteger(rawStatus) && rawStatus >= 400 && rawStatus <= 599 ? rawStatus : 'unknown';
|
|
19
|
+
const exitStatus = Number.isInteger(result.status) && result.status >= 0 && result.status <= 255 ? result.status : 'unknown';
|
|
20
|
+
return {code, httpStatus, exitStatus};
|
|
21
|
+
}
|
|
22
|
+
export function publishReviewed({root, version, sha256, env = process.env, run = spawnSync, wait = () => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 2000)}) {
|
|
23
|
+
if (env.GITHUB_ACTIONS !== 'true' || env.GITHUB_EVENT_NAME !== 'workflow_dispatch' || env.GITHUB_REF !== 'refs/heads/dev') throw Error('Publishing requires manual GitHub Actions dispatch on dev');
|
|
24
|
+
if (env.GITHUB_REPOSITORY_VISIBILITY !== 'public') throw Error('Provenance publishing requires a public GitHub repository');
|
|
25
|
+
if (!env.NODE_AUTH_TOKEN?.trim()) throw Error('Missing NODE_AUTH_TOKEN; publication has no authentication fallback');
|
|
26
|
+
if (!/^\d+\.\d+\.\d+(?:-[\w.-]+)?$/.test(version || '') || !/^[a-f0-9]{64}$/.test(sha256 || '')) throw Error('Expected reviewed exact version and SHA-256');
|
|
27
|
+
const source = JSON.parse(readFileSync(path.join(root, 'package.json'), 'utf8'));
|
|
28
|
+
if (source.version !== version) throw Error('Reviewed version does not match source version');
|
|
29
|
+
const archive = path.join(root, 'artifacts', `${source.name.replace(/^@/, '').replace('/', '-')}-${version}.tgz`);
|
|
30
|
+
const bytes = readFileSync(archive);
|
|
31
|
+
if (createHash('sha256').update(bytes).digest('hex') !== sha256) throw Error('Reviewed archive SHA-256 mismatch');
|
|
32
|
+
const options = { cwd: root, encoding: 'utf8', env };
|
|
33
|
+
const metadataResult = run('tar', ['-xOf', archive, 'package/package.json'], options);
|
|
34
|
+
if (metadataResult.status !== 0) throw Error(metadataResult.stderr || 'Archive inspection failed');
|
|
35
|
+
const pkg = JSON.parse(metadataResult.stdout);
|
|
36
|
+
if (pkg.name !== source.name || pkg.version !== version || pkg.private || pkg.publishConfig?.access !== 'public' || pkg.publishConfig?.registry !== 'https://registry.npmjs.org/' || pkg.publishConfig?.tag !== 'next') throw Error('Expected reviewed staged registry candidate');
|
|
37
|
+
const integrity = 'sha512-' + createHash('sha512').update(bytes).digest('base64');
|
|
38
|
+
const lookupArgs = ['view', `${pkg.name}@${version}`, '--json', '--registry', 'https://registry.npmjs.org/'];
|
|
39
|
+
const lookupOptions = { ...options, timeout: 15000 };
|
|
40
|
+
const lookup = run('npm', lookupArgs, lookupOptions);
|
|
41
|
+
if (lookup.status === 0) {
|
|
42
|
+
const existing = JSON.parse(lookup.stdout);
|
|
43
|
+
if (existing.name !== pkg.name || existing.version !== version || existing.dist?.integrity !== integrity) throw Error('Published version exists with different identity or integrity');
|
|
44
|
+
return { name: pkg.name, version, sha256, integrity, published: false, alreadyPublished: true, registryConfirmed: true };
|
|
45
|
+
}
|
|
46
|
+
let error;
|
|
47
|
+
try { error = JSON.parse(lookup.stdout || '{}').error; } catch {}
|
|
48
|
+
if (error?.code !== 'E404') throw Error('Registry lookup failed; refusing publication');
|
|
49
|
+
const result = run('npm', ['publish', archive, '--ignore-scripts', '--access', 'public', '--tag', 'next', '--registry', 'https://registry.npmjs.org/', '--provenance', '--json'], options);
|
|
50
|
+
if (result.status !== 0) {
|
|
51
|
+
const {code, httpStatus, exitStatus} = npmFailure(result);
|
|
52
|
+
throw Error(`npm publish failed for ${pkg.name}@${version}: code=${code}, httpStatus=${httpStatus}, exitStatus=${exitStatus}`);
|
|
53
|
+
}
|
|
54
|
+
let visible = false;
|
|
55
|
+
for (let attempt = 0; attempt < 3; attempt++) {
|
|
56
|
+
if (attempt) wait();
|
|
57
|
+
const confirmation = run('npm', lookupArgs, lookupOptions);
|
|
58
|
+
if (confirmation.status === 0) {
|
|
59
|
+
let existing;
|
|
60
|
+
try { existing = JSON.parse(confirmation.stdout); } catch {}
|
|
61
|
+
if (existing?.name !== pkg.name || existing?.version !== version || existing?.dist?.integrity !== integrity) throw Error('Postpublication registry identity or integrity mismatch');
|
|
62
|
+
visible = true;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
if (!visible) throw Error(`npm publication returned success but registry confirmation failed for ${pkg.name}@${version}; publication was not retried`);
|
|
67
|
+
return { name: pkg.name, version, sha256, integrity, published: true, alreadyPublished: false, registryConfirmed: true };
|
|
68
|
+
}
|
|
69
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === fileURLToPath(import.meta.url)) {
|
|
70
|
+
assertReleaseTooling();
|
|
71
|
+
console.log(JSON.stringify(publishReviewed({root: fileURLToPath(new URL('../', import.meta.url)), version: process.argv[2], sha256: process.argv[3]})));
|
|
72
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema": 1,
|
|
3
|
+
"canonical": "knightseye-net/tools/release-tooling",
|
|
4
|
+
"sha256": {
|
|
5
|
+
"scripts/pack.mjs": "334aa4041e59b14fd2b072969f50beea64449136f7f9146d63d7277fc2e4808a",
|
|
6
|
+
"scripts/publish-reviewed.mjs": "e9e8a6f5eeff37d5050b96e75fda2fa33084b1f9bc5d5a6688b0aef737dd51c5",
|
|
7
|
+
".github/workflows/npm-publish.yml": "b25cec136db205d69a407284dae2bb66f3d56be13ed2a1367f0db167a232050d",
|
|
8
|
+
"scripts/verify-release.mjs": "d0f9baead779e553385bb7c26f1238ad4e60a189a818d4db4f721a1e5f88dedc",
|
|
9
|
+
"scripts/update-dependency.mjs": "9919f172be33973f124eabf56c1dc70e41e941e601783ef01aba1c47dd70db9d",
|
|
10
|
+
"scripts/check-release-tooling.mjs": "29563619bdc3e86ef10dec1e983274e36138193f04d33f2455501b59a4016e0d",
|
|
11
|
+
".github/workflows/quality.yml": "a014920a9f89dc494a020bee5f69aec779cf58825f491690f9ed1ec089ed6fa0"
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Generated from knightseye-net/tools/release-tooling; edit the canonical template and sync.
|
|
2
|
+
import { assertReleaseTooling } from './check-release-tooling.mjs';
|
|
3
|
+
assertReleaseTooling();
|
|
4
|
+
import {readFileSync,writeFileSync,mkdirSync,existsSync,copyFileSync} from 'node:fs';
|
|
5
|
+
import {createHash} from 'node:crypto';
|
|
6
|
+
import {spawnSync} from 'node:child_process';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import { fileURLToPath } from 'node:url';
|
|
9
|
+
process.chdir(fileURLToPath(new URL('../', import.meta.url)));
|
|
10
|
+
const [name,input,registryVersion]=process.argv.slice(2);
|
|
11
|
+
const exact=/^\d+\.\d+\.\d+(?:-[\w.-]+)?$/;
|
|
12
|
+
if(!name?.startsWith('@knights-eye-chess/')||!input)throw Error('Usage: node scripts/update-dependency.mjs @knights-eye-chess/name /absolute/package.tgz | --registry EXACT_VERSION | EXACT_VERSION');
|
|
13
|
+
const pkg=JSON.parse(readFileSync('package.json','utf8'));
|
|
14
|
+
if(!pkg.dependencies?.[name])throw Error('Not an existing package dependency');
|
|
15
|
+
const version=input==='--registry'?registryVersion:exact.test(input)?input:null;
|
|
16
|
+
if(input==='--registry'||version){
|
|
17
|
+
if(!exact.test(version||''))throw Error('Expected exact registry version');
|
|
18
|
+
const probe=spawnSync('npm',['view',`${name}@${version}`,'--json','--registry','https://registry.npmjs.org/'],{encoding:'utf8'});
|
|
19
|
+
if(probe.status!==0)throw Error(probe.stderr||'Registry lookup failed');
|
|
20
|
+
const metadata=JSON.parse(probe.stdout);
|
|
21
|
+
if(metadata.name!==name||metadata.version!==version)throw Error('Registry identity/version mismatch');
|
|
22
|
+
pkg.dependencies[name]=version;
|
|
23
|
+
const release=JSON.parse(readFileSync('npm-release.json','utf8'));
|
|
24
|
+
release.registryDependencies ||= {};
|
|
25
|
+
release.registryDependencies[name]=version;
|
|
26
|
+
writeFileSync('npm-release.json',JSON.stringify(release,null,2)+'\n');
|
|
27
|
+
writeFileSync('package.json',JSON.stringify(pkg,null,2)+'\n');
|
|
28
|
+
const lock=spawnSync('npm',['install','--package-lock-only','--ignore-scripts','--registry','https://registry.npmjs.org/'],{stdio:'inherit'});
|
|
29
|
+
if(lock.status!==0)process.exit(lock.status||1);
|
|
30
|
+
console.log(JSON.stringify({name,version,registry:'https://registry.npmjs.org/'}));
|
|
31
|
+
}else{
|
|
32
|
+
const archive=path.resolve(input);
|
|
33
|
+
const probe=spawnSync('tar',['-xOf',archive,'package/package.json'],{encoding:'utf8'});
|
|
34
|
+
if(probe.status!==0)throw Error(probe.stderr);
|
|
35
|
+
const metadata=JSON.parse(probe.stdout);
|
|
36
|
+
if(!exact.test(metadata.version||'')||metadata.name!==name||(metadata.private!==true && !(metadata.publishConfig?.registry==='https://registry.npmjs.org/' && metadata.publishConfig?.access==='public' && metadata.publishConfig?.tag==='next')))throw Error('Expected matching private preview or registry candidate');
|
|
37
|
+
const file=path.basename(archive),destination='vendor/npm/'+file;
|
|
38
|
+
const bytes=readFileSync(archive),sha256=createHash('sha256').update(bytes).digest('hex');
|
|
39
|
+
mkdirSync('vendor/npm',{recursive:true});
|
|
40
|
+
if(existsSync(destination)&&createHash('sha256').update(readFileSync(destination)).digest('hex')!==sha256)throw Error('Refusing to overwrite a different immutable archive');
|
|
41
|
+
copyFileSync(archive,destination);pkg.dependencies[name]='file:'+destination;writeFileSync('package.json',JSON.stringify(pkg,null,2)+'\n');
|
|
42
|
+
const lock=spawnSync('npm',['install','--package-lock-only','--ignore-scripts'],{stdio:'inherit'});if(lock.status!==0)process.exit(lock.status||1);
|
|
43
|
+
console.log(JSON.stringify({name,version:metadata.version,archive:destination,sha256}));
|
|
44
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Generated from knightseye-net/tools/release-tooling; edit the canonical template and sync.
|
|
2
|
+
import { assertReleaseTooling } from './check-release-tooling.mjs';
|
|
3
|
+
assertReleaseTooling();
|
|
4
|
+
import { readFileSync, mkdtempSync, rmSync, existsSync, readdirSync } from 'node:fs';
|
|
5
|
+
import { spawnSync } from 'node:child_process';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import path from 'node:path';
|
|
8
|
+
import os from 'node:os';
|
|
9
|
+
|
|
10
|
+
const root = fileURLToPath(new URL('../', import.meta.url));
|
|
11
|
+
const source = JSON.parse(readFileSync(path.join(root, 'package.json'), 'utf8'));
|
|
12
|
+
const name = source.name.replace(/^@/, '').replace('/', '-');
|
|
13
|
+
const archive = path.resolve(process.argv[2] || path.join(root, 'artifacts', `${name}-${source.version}.tgz`));
|
|
14
|
+
const stage = mkdtempSync(path.join(os.tmpdir(), 'knights-eye-verify-'));
|
|
15
|
+
function run(command, args) {
|
|
16
|
+
const result = spawnSync(command, args, { cwd: root, encoding: 'utf8' });
|
|
17
|
+
if (result.status !== 0) throw Error(result.stderr || result.stdout || `${command} failed`);
|
|
18
|
+
return result.stdout;
|
|
19
|
+
}
|
|
20
|
+
function requirePath(relative) {
|
|
21
|
+
if (!relative.startsWith('./') || relative.includes('..')) throw Error(`Invalid package target: ${relative}`);
|
|
22
|
+
const target = path.join(stage, 'package', relative);
|
|
23
|
+
if (relative.includes('*')) {
|
|
24
|
+
const directory = path.dirname(target);
|
|
25
|
+
if (!existsSync(directory) || !readdirSync(directory).length) throw Error(`Missing exported assets: ${relative}`);
|
|
26
|
+
} else if (!existsSync(target)) throw Error(`Missing package target: ${relative}`);
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
run('tar', ['-xzf', archive, '-C', stage]);
|
|
30
|
+
const pkg = JSON.parse(readFileSync(path.join(stage, 'package/package.json'), 'utf8'));
|
|
31
|
+
if (pkg.name !== source.name || pkg.version !== source.version || pkg.private) throw Error('Unexpected identity or private package');
|
|
32
|
+
if (pkg.publishConfig?.access !== 'public' || pkg.publishConfig.registry !== 'https://registry.npmjs.org/' || pkg.publishConfig.tag !== 'next') throw Error('Expected public npm prerelease settings');
|
|
33
|
+
if (existsSync(path.join(stage, 'package/npm-shrinkwrap.json')) || existsSync(path.join(stage, 'package/vendor'))) throw Error('Source-only dependency pins leaked into the consumer package');
|
|
34
|
+
for (const section of ['dependencies', 'optionalDependencies', 'peerDependencies', 'devDependencies']) {
|
|
35
|
+
for (const [dependency, version] of Object.entries(pkg[section] || {})) {
|
|
36
|
+
if (/^(file:|link:|workspace:|https?:|git)/.test(version)) throw Error(`Non-registry dependency: ${dependency}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
for (const [subpath, entry] of Object.entries(pkg.exports || {})) {
|
|
40
|
+
if (typeof entry === 'string') requirePath(entry);
|
|
41
|
+
else {
|
|
42
|
+
if (!entry.types || !entry.import) throw Error(`Missing runtime/types export: ${subpath}`);
|
|
43
|
+
requirePath(entry.types); requirePath(entry.import);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
for (const entry of Object.values(pkg.bin || {})) requirePath('./' + entry.replace(/^\.\//, ''));
|
|
47
|
+
for (const file of ['LICENSE', 'NOTICE', 'LICENSING.md', 'THIRD_PARTY_NOTICES.md', 'SOURCE-ORIGIN.json', 'NPM-PUBLISHING.md']) requirePath('./' + file);
|
|
48
|
+
const dryRun = JSON.parse(run('npm', ['publish', archive, '--dry-run', '--ignore-scripts', '--access', 'public', '--tag', 'next', '--registry', 'https://registry.npmjs.org/', '--json']));
|
|
49
|
+
console.log(JSON.stringify({ package: pkg.name, version: pkg.version, archive, registryDependencies: pkg.dependencies || {}, files: dryRun.files?.length, dryRun: true, registryWrite: false }, null, 2));
|
|
50
|
+
} finally {
|
|
51
|
+
rmSync(stage, { recursive: true, force: true });
|
|
52
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Public finite error vocabulary. Never copy arbitrary provider text or transport bodies. */
|
|
2
|
+
export type AiFailureDetails = { code: string; status?: number; retryAfterSeconds?: number; providerDispatched?: boolean; requestId?: string; providerRequestId?: string; stage: string; reportable: boolean };
|
|
3
|
+
const known = new Set(['insufficient_credits','invalid_key','rate_limited','model_unavailable','provider_unavailable','free_unavailable','free_funds_exhausted','ai_request_active','ai_hourly_limit','ai_admission_busy','sign_in_required','forbidden','connection_changed','cancelled','request_too_large','request_timeout','network_error','response_invalid','unknown_error','tool_evidence_contract_failed','output_truncated','empty_answer','no_final_answer','context_byte_budget']);
|
|
4
|
+
const expected = new Set(['insufficient_credits','invalid_key','rate_limited','model_unavailable','free_unavailable','free_funds_exhausted','ai_hourly_limit','sign_in_required','forbidden','connection_changed','cancelled']);
|
|
5
|
+
export function aiFailureDetails(code: string, fields: Partial<AiFailureDetails> = {}): AiFailureDetails {
|
|
6
|
+
code = known.has(code) ? code : 'unknown_error';
|
|
7
|
+
return { ...fields, code, stage: fields.stage || 'simple-model', reportable: !expected.has(code) };
|
|
8
|
+
}
|
|
9
|
+
export function aiFailureMessage(f: AiFailureDetails, reported = false): string {
|
|
10
|
+
const minutes = Math.max(1, Math.ceil((f.retryAfterSeconds ?? 0) / 60));
|
|
11
|
+
const wait = f.retryAfterSeconds ? ` Please try again in about ${minutes} ${minutes === 1 ? 'minute' : 'minutes'}.` : ' Please wait a moment and try again.';
|
|
12
|
+
switch(f.code) {
|
|
13
|
+
case 'ai_request_active': return 'Your previous AI request is still processing or being released after it stopped.' + wait;
|
|
14
|
+
case 'ai_hourly_limit': return 'The hourly AI allowance has been reached.' + wait;
|
|
15
|
+
case 'rate_limited': return 'Your AI provider is temporarily limiting requests.' + wait;
|
|
16
|
+
case 'insufficient_credits': return 'Your AI account has insufficient credits or reached its spending limit. Add credits or adjust the limit, then try again.';
|
|
17
|
+
case 'invalid_key': case 'connection_changed': return 'Your AI connection needs attention. Open your profile and reconnect your AI account.';
|
|
18
|
+
case 'sign_in_required': return 'Your session has expired. Please sign in again to ask a question.';
|
|
19
|
+
case 'forbidden': return 'You cannot ask questions about this game with the current account. Sign in to the owning account or create your own copy.';
|
|
20
|
+
case 'model_unavailable': return 'The selected model is unavailable. Check your AI connection in your profile or try again later.';
|
|
21
|
+
case 'free_unavailable': case 'free_funds_exhausted': return 'Free AI is temporarily unavailable. Connect your own AI account in your profile, or try again later.';
|
|
22
|
+
case 'cancelled': return 'The request was cancelled.';
|
|
23
|
+
case 'network_error': return 'We could not reach the AI service. Check your internet connection and try again.';
|
|
24
|
+
case 'request_timeout': return 'The AI request took too long. Please try again later. The provider may have charged for this attempt.';
|
|
25
|
+
case 'request_too_large': case 'context_byte_budget': return 'This question and its context are too large to send. Try a shorter question or start a new chat.';
|
|
26
|
+
default: return reported ? "Something went wrong. We've received an automatic report and will look into it. Please try again." : 'Something went wrong. Please try again. You can also report this problem to us.';
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
export function failureFromError(error: unknown, code = 'unknown_error'): AiFailureDetails {
|
|
30
|
+
const e = error as { details?: AiFailureDetails; name?: string } | null;
|
|
31
|
+
if(e?.details) return e.details;
|
|
32
|
+
if(e?.name === 'AbortError') return aiFailureDetails('cancelled');
|
|
33
|
+
return aiFailureDetails(code);
|
|
34
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** Public, bounded routing facts only. Never provider text, headers or credentials. */
|
|
2
|
+
export const AI_ROUTING_HEADER = 'x-knights-eye-ai-routing';
|
|
3
|
+
export type AiRoutingDiagnostics = {
|
|
4
|
+
requestedTier: 'flex' | 'default' | 'priority' | null;
|
|
5
|
+
actualTier: 'flex' | 'default' | 'priority' | null;
|
|
6
|
+
reason: 'flex_available' | 'cooldown_active' | 'storage_unavailable' | 'unsupported' | 'user_disabled' | 'user_standard' | 'user_fast';
|
|
7
|
+
elapsedMs: number;
|
|
8
|
+
slowThresholdMs: number;
|
|
9
|
+
timingEligible?: boolean;
|
|
10
|
+
cooldownUntil: number | null;
|
|
11
|
+
cooldownTriggered: boolean;
|
|
12
|
+
persistenceError?: boolean;
|
|
13
|
+
};
|
|
14
|
+
export function readAiRoutingDiagnostics(headers?: Headers | Record<string, string>): AiRoutingDiagnostics | undefined {
|
|
15
|
+
try {
|
|
16
|
+
const raw = headers instanceof Headers ? headers.get(AI_ROUTING_HEADER) : headers?.[AI_ROUTING_HEADER];
|
|
17
|
+
if (!raw || raw.length > 2048) return undefined;
|
|
18
|
+
const value = JSON.parse(raw);
|
|
19
|
+
if (!value || ![null,'flex','default','priority'].includes(value.requestedTier)
|
|
20
|
+
|| ![null,'flex','default','priority'].includes(value.actualTier)
|
|
21
|
+
|| !['flex_available','cooldown_active','storage_unavailable','unsupported','user_disabled','user_standard','user_fast'].includes(value.reason)
|
|
22
|
+
|| !Number.isFinite(value.elapsedMs) || value.elapsedMs < 0
|
|
23
|
+
|| !Number.isFinite(value.slowThresholdMs) || value.slowThresholdMs <= 0
|
|
24
|
+
|| (value.cooldownUntil !== null && (!Number.isSafeInteger(value.cooldownUntil) || value.cooldownUntil < 0))
|
|
25
|
+
|| typeof value.cooldownTriggered !== 'boolean'
|
|
26
|
+
|| (value.timingEligible !== undefined && typeof value.timingEligible !== 'boolean')) return undefined;
|
|
27
|
+
return {requestedTier:value.requestedTier,actualTier:value.actualTier,reason:value.reason,
|
|
28
|
+
elapsedMs:value.elapsedMs,slowThresholdMs:value.slowThresholdMs,cooldownUntil:value.cooldownUntil,
|
|
29
|
+
cooldownTriggered:value.cooldownTriggered,
|
|
30
|
+
...(typeof value.timingEligible === 'boolean' ? {timingEligible:value.timingEligible} : {}),
|
|
31
|
+
...(value.persistenceError === true ? {persistenceError:true} : {})};
|
|
32
|
+
} catch { return undefined; }
|
|
33
|
+
}
|