@entrorove/skill 0.1.22 → 0.1.24
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/AGREEMENT.md +6 -6
- package/CHANGELOG.md +10 -0
- package/SKILL.md +12 -4
- package/archguard-runtime-build.mjs +15 -0
- package/blueprint-criterion-runner.mjs +110 -0
- package/blueprint-criterion-wire.mjs +78 -0
- package/calctool-runtime-build.mjs +59 -0
- package/calctool-runtime-entry.mjs +92 -0
- package/cli.mjs +18 -83
- package/local-approved-plan.mjs +74 -15
- package/local-archguard-ast.mjs +371 -0
- package/local-archguard-checkpoint.mjs +123 -0
- package/local-archguard-components.mjs +177 -0
- package/local-archguard-contract.mjs +109 -0
- package/local-archguard-contracts.mjs +42 -0
- package/local-archguard-evaluate.mjs +120 -0
- package/local-archguard-language-ast.mjs +165 -0
- package/local-archguard-mutation-fence.mjs +28 -0
- package/local-archguard-operations.mjs +25 -0
- package/local-archguard-scope.mjs +64 -0
- package/local-archguard-signing.mjs +52 -0
- package/local-archguard-snapshot.mjs +126 -0
- package/local-archguard-state.mjs +200 -0
- package/local-archguard.mjs +74 -0
- package/local-budget-git-attributes.mjs +49 -0
- package/local-budget-git-loader.mjs +61 -0
- package/local-budget-git-native-attributes.mjs +81 -0
- package/local-budget-git-native-darwin.mjs +104 -0
- package/local-budget-git-native-linux.mjs +93 -0
- package/local-budget-git-native-reads.mjs +88 -0
- package/local-budget-git-native-request.mjs +53 -0
- package/local-budget-git-native-runtime.mjs +18 -0
- package/local-budget-git-native.c +313 -0
- package/local-budget-git-native.mjs +109 -0
- package/local-budget-git-outcome.mjs +33 -0
- package/local-budget-git-scratch-loader.mjs +158 -0
- package/local-budget-git-scratch.mjs +112 -0
- package/local-budget-git-system-attributes.mjs +44 -0
- package/local-budget-git.mjs +92 -0
- package/local-budget-grants.mjs +82 -0
- package/local-budget-handoff-completion.mjs +70 -0
- package/local-budget-handoff-contracts.mjs +53 -0
- package/local-budget-handoff.mjs +229 -0
- package/local-budget-lock.mjs +55 -0
- package/local-budget-reads.mjs +135 -0
- package/local-budget-renewal.mjs +86 -34
- package/local-budget-source-bindings.mjs +51 -0
- package/local-budget-store.mjs +131 -0
- package/local-budget-transition.mjs +46 -0
- package/local-budget.mjs +185 -0
- package/local-calctool-cli.mjs +22 -0
- package/local-calctool-contracts.mjs +42 -0
- package/local-calctool-runtime.mjs +10 -0
- package/local-calctool-storage.mjs +101 -0
- package/local-calctool.mjs +103 -0
- package/local-cli.mjs +49 -16
- package/local-contract-types.mjs +46 -0
- package/local-contracts.mjs +124 -0
- package/local-credential.mjs +101 -0
- package/local-decimal.mjs +85 -0
- package/local-evidence-verification.mjs +199 -0
- package/local-execution.mjs +115 -304
- package/local-final-gate16-bundle.mjs +21 -0
- package/local-final-gate16-checks.mjs +88 -0
- package/local-final-gate16-contract.mjs +15 -0
- package/local-final-gate16-plan.mjs +66 -0
- package/local-final-gate16-proof.mjs +75 -0
- package/local-final-gate16-release.mjs +17 -0
- package/local-final-gate16-state.mjs +70 -0
- package/local-final-gate16-worker.mjs +19 -0
- package/local-final-gate16.mjs +137 -0
- package/local-formula-ast.mjs +97 -0
- package/local-formula-engine.mjs +111 -0
- package/local-formula-tests.mjs +61 -0
- package/local-formula.mjs +25 -125
- package/local-integrity.mjs +22 -41
- package/local-invocations.mjs +107 -0
- package/local-ledger.mjs +2 -7
- package/local-merge-archguard-verification.d.mts +44 -0
- package/local-merge-archguard-verification.mjs +240 -0
- package/local-merge-archguard.mjs +138 -0
- package/local-merge-artifacts.mjs +86 -0
- package/local-merge-authority.mjs +89 -0
- package/local-merge-contracts.mjs +56 -0
- package/local-merge-controller.mjs +170 -0
- package/local-merge-head.mjs +56 -0
- package/local-merge-journal.mjs +77 -0
- package/local-merge-mutation.mjs +97 -0
- package/local-merge-rollback.mjs +126 -0
- package/local-merge-snapshot-rollback.mjs +26 -0
- package/local-merge-storage.mjs +103 -0
- package/local-merge-targets.mjs +47 -0
- package/local-merge-transaction.mjs +133 -0
- package/local-mutation-audit.mjs +34 -0
- package/local-mutation-authority.mjs +96 -0
- package/local-mutation-batch-receipt.mjs +84 -0
- package/local-mutation-batch.mjs +143 -0
- package/local-mutation-binding.mjs +86 -0
- package/local-mutation-files.mjs +245 -0
- package/local-mutation-pass-store.mjs +63 -0
- package/local-mutation-snapshot.mjs +200 -0
- package/local-mutation-wire.mjs +89 -0
- package/local-probe.mjs +133 -11
- package/local-scope-candidate.mjs +28 -0
- package/local-scope-context.mjs +28 -0
- package/local-scope-files.mjs +106 -0
- package/local-scope-git-attributes.mjs +200 -0
- package/local-scope-git-comparison.mjs +8 -0
- package/local-scope-git-history.mjs +72 -0
- package/local-scope-git-reads.mjs +66 -0
- package/local-scope-git.mjs +124 -0
- package/local-scope-repository.mjs +249 -0
- package/local-scope-signature.mjs +70 -0
- package/local-scope-snapshot.mjs +39 -0
- package/local-scope-state.mjs +204 -0
- package/local-scope-workspaces.mjs +83 -0
- package/local-swarm-authority.mjs +143 -0
- package/local-swarm-baseline.mjs +32 -0
- package/local-swarm-completion.mjs +102 -0
- package/local-swarm-contracts.mjs +47 -0
- package/local-swarm-mutation.mjs +142 -0
- package/local-swarm-priority.mjs +237 -0
- package/local-swarm-state.mjs +102 -0
- package/local-swarm-storage.mjs +135 -0
- package/local-swarm.mjs +179 -0
- package/local-task-handoff-completion-wire.mjs +71 -0
- package/local-task-handoff-contracts.mjs +66 -0
- package/local-task-handoff-fence.mjs +478 -0
- package/local-task-handoff-observation.mjs +38 -0
- package/local-task-handoff-overlay-wire.mjs +94 -0
- package/local-task-handoff-read-authority.mjs +236 -0
- package/local-task-handoff-storage.mjs +73 -0
- package/local-task-handoff-write-archive.mjs +80 -0
- package/local-task-handoff-write-constraints.mjs +66 -0
- package/local-task-handoff-write-receipts.mjs +99 -0
- package/local-task-handoff-write-wire.mjs +99 -0
- package/local-task-routing.mjs +202 -22
- package/manifest.json +1 -1
- package/package.json +153 -3
- package/release-state.json +153 -17
- package/release.mjs +238 -4
- package/releases.json +12 -0
- package/remote-client.mjs +127 -36
- package/remote-transport.mjs +80 -0
- package/review-client.mjs +38 -0
- package/runtime/archguard-runtime-v7.0.44.mjs +314 -0
- package/runtime/calctool-runtime-v7.0.43.mjs +1887 -0
- package/runtime/git-native-darwin-v1.mjs +5 -0
- package/runtime/git-native-linux-v1.mjs +5 -0
- package/task-message-cli.mjs +47 -0
- package/task-message-entry.mjs +159 -0
- package/workflow-local-client.mjs +35 -0
- package/workflow-local-contracts.mjs +58 -0
- package/workflow-local-request.mjs +53 -0
- package/workflow-local-runner.mjs +350 -0
package/release.mjs
CHANGED
|
@@ -1,15 +1,127 @@
|
|
|
1
|
+
import { FINAL_GATE16_PACKAGE_FILES, withFinalGate16ReleaseLabels } from './local-final-gate16-release.mjs'
|
|
1
2
|
import { createHash } from 'node:crypto'
|
|
2
3
|
import { readFile, writeFile, rename, rm } from 'node:fs/promises'
|
|
3
4
|
import path from 'node:path'
|
|
4
5
|
import { fileURLToPath } from 'node:url'
|
|
5
6
|
|
|
6
7
|
const directory = path.dirname(fileURLToPath(import.meta.url))
|
|
8
|
+
const swarmSourceFiles = Object.freeze([
|
|
9
|
+
'local-swarm-authority.mjs',
|
|
10
|
+
'local-swarm-baseline.mjs',
|
|
11
|
+
'local-swarm-completion.mjs',
|
|
12
|
+
'local-swarm-contracts.mjs',
|
|
13
|
+
'local-swarm-mutation.mjs',
|
|
14
|
+
'local-swarm-priority.mjs',
|
|
15
|
+
'local-swarm-state.mjs',
|
|
16
|
+
'local-swarm-storage.mjs',
|
|
17
|
+
'local-swarm.mjs',
|
|
18
|
+
])
|
|
7
19
|
const sourceFiles = [
|
|
8
|
-
|
|
20
|
+
...FINAL_GATE16_PACKAGE_FILES,
|
|
21
|
+
'local-merge-archguard-verification.d.mts',
|
|
22
|
+
'local-merge-archguard-verification.mjs',
|
|
23
|
+
'local-merge-archguard.mjs',
|
|
24
|
+
'local-merge-artifacts.mjs',
|
|
25
|
+
'local-merge-authority.mjs',
|
|
26
|
+
'local-merge-contracts.mjs',
|
|
27
|
+
'local-merge-controller.mjs',
|
|
28
|
+
'local-merge-head.mjs',
|
|
29
|
+
'local-merge-journal.mjs',
|
|
30
|
+
'local-merge-mutation.mjs',
|
|
31
|
+
'local-merge-rollback.mjs',
|
|
32
|
+
'local-merge-snapshot-rollback.mjs',
|
|
33
|
+
'local-merge-storage.mjs',
|
|
34
|
+
'local-merge-targets.mjs',
|
|
35
|
+
'local-merge-transaction.mjs',
|
|
36
|
+
...swarmSourceFiles,
|
|
37
|
+
'cli.mjs', 'review-client.mjs', 'version.mjs', 'SKILL.md', 'CAPABILITY-MAP.md', 'AGREEMENT.md',
|
|
9
38
|
'package.json', 'manifest.json', 'release.mjs',
|
|
10
|
-
'local-cli.mjs', 'local-state-lock.mjs', 'local-execution.mjs', 'local-integrity.mjs', 'local-formula.mjs', 'local-ledger.mjs',
|
|
39
|
+
'local-cli.mjs', 'local-state-lock.mjs', 'local-execution.mjs', 'local-integrity.mjs', 'local-evidence-verification.mjs', 'local-formula.mjs', 'local-ledger.mjs',
|
|
40
|
+
'blueprint-criterion-wire.mjs', 'blueprint-criterion-runner.mjs',
|
|
11
41
|
'local-approved-plan.mjs', 'local-budget-renewal.mjs', 'local-probe.mjs',
|
|
42
|
+
'local-budget-grants.mjs', 'local-budget-handoff.mjs', 'local-budget-handoff-contracts.mjs', 'local-budget-lock.mjs',
|
|
43
|
+
'local-budget-handoff-completion.mjs',
|
|
44
|
+
'local-budget-reads.mjs', 'local-budget-source-bindings.mjs', 'local-budget-store.mjs',
|
|
45
|
+
'local-budget-transition.mjs', 'local-budget.mjs',
|
|
46
|
+
'local-scope-candidate.mjs',
|
|
47
|
+
'local-scope-context.mjs',
|
|
48
|
+
'local-scope-files.mjs',
|
|
49
|
+
'local-scope-repository.mjs',
|
|
50
|
+
'local-scope-git.mjs',
|
|
51
|
+
'local-scope-git-reads.mjs',
|
|
52
|
+
'local-scope-git-comparison.mjs',
|
|
53
|
+
'local-scope-git-attributes.mjs',
|
|
54
|
+
'local-scope-git-history.mjs',
|
|
55
|
+
'local-budget-git.mjs',
|
|
56
|
+
'local-budget-git-loader.mjs',
|
|
57
|
+
'local-budget-git-scratch.mjs',
|
|
58
|
+
'local-budget-git-scratch-loader.mjs',
|
|
59
|
+
'local-budget-git-attributes.mjs',
|
|
60
|
+
'local-budget-git-native-attributes.mjs',
|
|
61
|
+
'local-budget-git-native-reads.mjs',
|
|
62
|
+
'local-budget-git-native-request.mjs',
|
|
63
|
+
'local-budget-git-native-runtime.mjs',
|
|
64
|
+
'local-budget-git-native.mjs',
|
|
65
|
+
'local-budget-git-native.c',
|
|
66
|
+
'local-budget-git-native-linux.mjs',
|
|
67
|
+
'local-budget-git-native-darwin.mjs',
|
|
68
|
+
'local-budget-git-outcome.mjs',
|
|
69
|
+
'local-budget-git-system-attributes.mjs',
|
|
70
|
+
'runtime/git-native-linux-v1.mjs',
|
|
71
|
+
'runtime/git-native-darwin-v1.mjs',
|
|
72
|
+
'local-scope-signature.mjs',
|
|
73
|
+
'local-scope-snapshot.mjs',
|
|
74
|
+
'local-scope-state.mjs',
|
|
75
|
+
'local-scope-workspaces.mjs',
|
|
12
76
|
'local-task-routing.mjs', 'remote-client.mjs',
|
|
77
|
+
'remote-transport.mjs', 'local-credential.mjs', 'local-invocations.mjs',
|
|
78
|
+
'local-task-handoff-fence.mjs',
|
|
79
|
+
'local-task-handoff-storage.mjs', 'local-task-handoff-overlay-wire.mjs', 'local-task-handoff-completion-wire.mjs',
|
|
80
|
+
'local-task-handoff-contracts.mjs',
|
|
81
|
+
'local-task-handoff-write-constraints.mjs',
|
|
82
|
+
'local-task-handoff-observation.mjs', 'local-task-handoff-write-wire.mjs',
|
|
83
|
+
'local-task-handoff-read-authority.mjs',
|
|
84
|
+
'local-task-handoff-write-archive.mjs', 'local-task-handoff-write-receipts.mjs',
|
|
85
|
+
'workflow-local-runner.mjs', 'workflow-local-contracts.mjs', 'workflow-local-client.mjs', 'workflow-local-request.mjs',
|
|
86
|
+
'task-message-entry.mjs', 'task-message-cli.mjs',
|
|
87
|
+
'local-contracts.mjs', 'local-contract-types.mjs',
|
|
88
|
+
'local-archguard-ast.mjs',
|
|
89
|
+
'local-archguard-checkpoint.mjs',
|
|
90
|
+
'local-archguard-components.mjs',
|
|
91
|
+
'local-archguard-contract.mjs',
|
|
92
|
+
'local-archguard-contracts.mjs',
|
|
93
|
+
'local-archguard-evaluate.mjs',
|
|
94
|
+
'local-archguard-language-ast.mjs',
|
|
95
|
+
'local-archguard-mutation-fence.mjs',
|
|
96
|
+
'local-archguard-operations.mjs',
|
|
97
|
+
'local-archguard-scope.mjs',
|
|
98
|
+
'local-archguard-signing.mjs',
|
|
99
|
+
'local-archguard-snapshot.mjs',
|
|
100
|
+
'local-archguard-state.mjs',
|
|
101
|
+
'local-archguard.mjs',
|
|
102
|
+
'archguard-runtime-build.mjs',
|
|
103
|
+
'runtime/archguard-runtime-v7.0.44.mjs',
|
|
104
|
+
'local-decimal.mjs',
|
|
105
|
+
'local-formula-ast.mjs',
|
|
106
|
+
'local-formula-engine.mjs',
|
|
107
|
+
'local-formula-tests.mjs',
|
|
108
|
+
'local-calctool.mjs',
|
|
109
|
+
'local-calctool-cli.mjs',
|
|
110
|
+
'local-calctool-contracts.mjs',
|
|
111
|
+
'local-calctool-runtime.mjs',
|
|
112
|
+
'local-calctool-storage.mjs',
|
|
113
|
+
'local-mutation-files.mjs',
|
|
114
|
+
'local-mutation-snapshot.mjs',
|
|
115
|
+
'local-mutation-audit.mjs',
|
|
116
|
+
'local-mutation-wire.mjs',
|
|
117
|
+
'local-mutation-binding.mjs',
|
|
118
|
+
'local-mutation-pass-store.mjs',
|
|
119
|
+
'local-mutation-authority.mjs',
|
|
120
|
+
'local-mutation-batch.mjs',
|
|
121
|
+
'local-mutation-batch-receipt.mjs',
|
|
122
|
+
'calctool-runtime-entry.mjs',
|
|
123
|
+
'calctool-runtime-build.mjs',
|
|
124
|
+
'runtime/calctool-runtime-v7.0.43.mjs',
|
|
13
125
|
]
|
|
14
126
|
const stateFile = 'release-state.json'
|
|
15
127
|
const changelogFile = 'CHANGELOG.md'
|
|
@@ -49,6 +161,63 @@ function versionNext(version) {
|
|
|
49
161
|
return `${parts[0]}.${parts[1]}.${parts[2] + 1}`
|
|
50
162
|
}
|
|
51
163
|
|
|
164
|
+
const calctoolReleaseLabels = Object.freeze({
|
|
165
|
+
'local-decimal.mjs': { zh: 'Calctool Decimal28 公式与本地执行', en: 'Calctool Decimal28 formulas and local execution' },
|
|
166
|
+
'local-formula-ast.mjs': { zh: 'Calctool Decimal28 公式与本地执行', en: 'Calctool Decimal28 formulas and local execution' },
|
|
167
|
+
'local-formula-engine.mjs': { zh: 'Calctool Decimal28 公式与本地执行', en: 'Calctool Decimal28 formulas and local execution' },
|
|
168
|
+
'local-formula-tests.mjs': { zh: 'Calctool Decimal28 公式与本地执行', en: 'Calctool Decimal28 formulas and local execution' },
|
|
169
|
+
'local-calctool.mjs': { zh: 'Calctool Decimal28 公式与本地执行', en: 'Calctool Decimal28 formulas and local execution' },
|
|
170
|
+
'local-calctool-cli.mjs': { zh: 'Calctool Decimal28 公式与本地执行', en: 'Calctool Decimal28 formulas and local execution' },
|
|
171
|
+
'local-calctool-contracts.mjs': { zh: 'Calctool Decimal28 公式与本地执行', en: 'Calctool Decimal28 formulas and local execution' },
|
|
172
|
+
'local-calctool-runtime.mjs': { zh: 'Calctool Decimal28 公式与本地执行', en: 'Calctool Decimal28 formulas and local execution' },
|
|
173
|
+
'local-calctool-storage.mjs': { zh: 'Calctool Decimal28 公式与本地执行', en: 'Calctool Decimal28 formulas and local execution' },
|
|
174
|
+
'calctool-runtime-entry.mjs': { zh: 'Calctool Decimal28 公式与本地执行', en: 'Calctool Decimal28 formulas and local execution' },
|
|
175
|
+
'calctool-runtime-build.mjs': { zh: 'Calctool Decimal28 公式与本地执行', en: 'Calctool Decimal28 formulas and local execution' },
|
|
176
|
+
'runtime/calctool-runtime-v7.0.43.mjs': { zh: 'Calctool Decimal28 公式与本地执行', en: 'Calctool Decimal28 formulas and local execution' },
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
const mutationReleaseLabels = Object.freeze({
|
|
180
|
+
'local-mutation-files.mjs': { zh: '原任务短时写入授权与文件快照隔离', en: 'Original task short-lived mutation authority and file snapshot isolation' },
|
|
181
|
+
'local-mutation-snapshot.mjs': { zh: '原任务短时写入授权与文件快照隔离', en: 'Original task short-lived mutation authority and file snapshot isolation' },
|
|
182
|
+
'local-mutation-audit.mjs': { zh: '原任务短时写入授权与文件快照隔离', en: 'Original task short-lived mutation authority and file snapshot isolation' },
|
|
183
|
+
'local-mutation-wire.mjs': { zh: '原任务短时写入授权与文件快照隔离', en: 'Original task short-lived mutation authority and file snapshot isolation' },
|
|
184
|
+
'local-mutation-binding.mjs': { zh: '原任务短时写入授权与文件快照隔离', en: 'Original task short-lived mutation authority and file snapshot isolation' },
|
|
185
|
+
'local-mutation-pass-store.mjs': { zh: '原任务短时写入授权与文件快照隔离', en: 'Original task short-lived mutation authority and file snapshot isolation' },
|
|
186
|
+
'local-mutation-authority.mjs': { zh: '原任务短时写入授权与文件快照隔离', en: 'Original task short-lived mutation authority and file snapshot isolation' },
|
|
187
|
+
'local-mutation-batch.mjs': { zh: '原任务批量写入消费与失败审计', en: 'Original task batch mutation consumption and failure audit' },
|
|
188
|
+
'local-mutation-batch-receipt.mjs': { zh: '原注册执行端批量消费签名回执', en: 'Registered runner signed batch consumption receipts' },
|
|
189
|
+
})
|
|
190
|
+
|
|
191
|
+
const swarmReleaseLabels = Object.freeze(Object.fromEntries(swarmSourceFiles.map(name => [name, {
|
|
192
|
+
zh: 'Swarm 原授权协作调度与实际执行守卫', en: 'Swarm original-authority coordination and actual execution guard',
|
|
193
|
+
}])))
|
|
194
|
+
|
|
195
|
+
const nativeReadReleaseLabels = {
|
|
196
|
+
'local-budget-git-attributes.mjs': { zh: '固定Git实际源读取与预算记账', en: 'fixed Git actual source reads and budget accounting' },
|
|
197
|
+
'local-budget-git-native-attributes.mjs': { zh: '固定Git实际源读取与预算记账', en: 'fixed Git actual source reads and budget accounting' },
|
|
198
|
+
'local-budget-git-native-reads.mjs': { zh: '固定Git实际源读取与预算记账', en: 'fixed Git actual source reads and budget accounting' },
|
|
199
|
+
'local-budget-git-native-request.mjs': { zh: '固定Git实际源读取与预算记账', en: 'fixed Git actual source reads and budget accounting' },
|
|
200
|
+
'local-budget-git-native-runtime.mjs': { zh: '固定Git实际源读取与预算记账', en: 'fixed Git actual source reads and budget accounting' },
|
|
201
|
+
'local-budget-git-native.mjs': { zh: '固定Git实际源读取与预算记账', en: 'fixed Git actual source reads and budget accounting' },
|
|
202
|
+
'local-budget-git-native.c': { zh: '固定Git实际源读取与预算记账', en: 'fixed Git actual source reads and budget accounting' },
|
|
203
|
+
'local-budget-git-native-linux.mjs': { zh: '固定Git实际源读取与预算记账', en: 'fixed Git actual source reads and budget accounting' },
|
|
204
|
+
'local-budget-git-native-darwin.mjs': { zh: '固定Git实际源读取与预算记账', en: 'fixed Git actual source reads and budget accounting' },
|
|
205
|
+
'local-budget-git-outcome.mjs': { zh: '固定Git实际源读取与预算记账', en: 'fixed Git actual source reads and budget accounting' },
|
|
206
|
+
'local-budget-git-system-attributes.mjs': { zh: '固定Git实际源读取与预算记账', en: 'fixed Git actual source reads and budget accounting' },
|
|
207
|
+
'runtime/git-native-linux-v1.mjs': { zh: '固定Git实际源读取与预算记账', en: 'fixed Git actual source reads and budget accounting' },
|
|
208
|
+
'runtime/git-native-darwin-v1.mjs': { zh: '固定Git实际源读取与预算记账', en: 'fixed Git actual source reads and budget accounting' },
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
const feedbackReleaseLabels = Object.freeze({
|
|
212
|
+
'review-client.mjs': { zh: '真实成功调用反馈绑定与明确公开同意', en: 'actual successful invocation feedback binding and explicit public consent' },
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
const invocationReleaseLabels = {
|
|
216
|
+
'remote-transport.mjs': { zh: '真实网络阶段与原请求恢复', en: 'Actual network phases and original request recovery' },
|
|
217
|
+
'local-credential.mjs': { zh: '唯一私有凭据与原子轮换', en: 'Single private credential and atomic rotation' },
|
|
218
|
+
'local-invocations.mjs': { zh: '无明文调用台账与用量对账', en: 'Metadata invocation ledger and usage reconciliation' },
|
|
219
|
+
}
|
|
220
|
+
|
|
52
221
|
function releaseNote(changed) {
|
|
53
222
|
const suppliedZh = process.env.ENTROROVE_RELEASE_NOTE_ZH?.trim()
|
|
54
223
|
const suppliedEn = process.env.ENTROROVE_RELEASE_NOTE_EN?.trim()
|
|
@@ -58,7 +227,25 @@ function releaseNote(changed) {
|
|
|
58
227
|
if (suppliedZh && suppliedEn) return {
|
|
59
228
|
zh: suppliedZh.replaceAll(/\s+/g, ' '), en: suppliedEn.replaceAll(/\s+/g, ' '),
|
|
60
229
|
}
|
|
61
|
-
const labels = {
|
|
230
|
+
const labels = withFinalGate16ReleaseLabels({ ...calctoolReleaseLabels, ...mutationReleaseLabels, ...swarmReleaseLabels, ...nativeReadReleaseLabels, ...feedbackReleaseLabels, ...invocationReleaseLabels,
|
|
231
|
+
'blueprint-criterion-wire.mjs': { zh: '蓝图验收标准执行授权', en: 'Blueprint criterion execution authority' },
|
|
232
|
+
'blueprint-criterion-runner.mjs': { zh: '蓝图验收标准实际执行器', en: 'Blueprint criterion process runner' },
|
|
233
|
+
'local-archguard-ast.mjs': { zh: 'Archguard 架构合同与执行守卫', en: 'Archguard architecture contract and execution guard' },
|
|
234
|
+
'local-archguard-checkpoint.mjs': { zh: 'Archguard 架构合同与执行守卫', en: 'Archguard architecture contract and execution guard' },
|
|
235
|
+
'local-archguard-components.mjs': { zh: 'Archguard 架构合同与执行守卫', en: 'Archguard architecture contract and execution guard' },
|
|
236
|
+
'local-archguard-contract.mjs': { zh: 'Archguard 架构合同与执行守卫', en: 'Archguard architecture contract and execution guard' },
|
|
237
|
+
'local-archguard-contracts.mjs': { zh: 'Archguard 架构合同与执行守卫', en: 'Archguard architecture contract and execution guard' },
|
|
238
|
+
'local-archguard-evaluate.mjs': { zh: 'Archguard 架构合同与执行守卫', en: 'Archguard architecture contract and execution guard' },
|
|
239
|
+
'local-archguard-language-ast.mjs': { zh: 'Archguard 架构合同与执行守卫', en: 'Archguard architecture contract and execution guard' },
|
|
240
|
+
'local-archguard-mutation-fence.mjs': { zh: 'Archguard 架构合同与执行守卫', en: 'Archguard architecture contract and execution guard' },
|
|
241
|
+
'local-archguard-operations.mjs': { zh: 'Archguard 架构合同与执行守卫', en: 'Archguard architecture contract and execution guard' },
|
|
242
|
+
'local-archguard-scope.mjs': { zh: 'Archguard 架构合同与执行守卫', en: 'Archguard architecture contract and execution guard' },
|
|
243
|
+
'local-archguard-signing.mjs': { zh: 'Archguard 架构合同与执行守卫', en: 'Archguard architecture contract and execution guard' },
|
|
244
|
+
'local-archguard-snapshot.mjs': { zh: 'Archguard 架构合同与执行守卫', en: 'Archguard architecture contract and execution guard' },
|
|
245
|
+
'local-archguard-state.mjs': { zh: 'Archguard 架构合同与执行守卫', en: 'Archguard architecture contract and execution guard' },
|
|
246
|
+
'local-archguard.mjs': { zh: 'Archguard 架构合同与执行守卫', en: 'Archguard architecture contract and execution guard' },
|
|
247
|
+
'archguard-runtime-build.mjs': { zh: 'Archguard 架构合同与执行守卫', en: 'Archguard architecture contract and execution guard' },
|
|
248
|
+
'runtime/archguard-runtime-v7.0.44.mjs': { zh: 'Archguard 架构合同与执行守卫', en: 'Archguard architecture contract and execution guard' },
|
|
62
249
|
'cli.mjs': { zh: '技能运行和受管安装', en: 'skill runtime and managed installation' },
|
|
63
250
|
'version.mjs': { zh: '版本安全检查', en: 'version safety checks' },
|
|
64
251
|
'SKILL.md': { zh: 'IDE 工作流程说明', en: 'IDE workflow instructions' },
|
|
@@ -68,17 +255,64 @@ function releaseNote(changed) {
|
|
|
68
255
|
'manifest.json': { zh: '技能清单', en: 'skill manifest' },
|
|
69
256
|
'release.mjs': { zh: '自动版本与更新日志', en: 'automatic versioning and changelog' },
|
|
70
257
|
'local-cli.mjs': { zh: '本地执行命令', en: 'local execution command' },
|
|
258
|
+
'local-contracts.mjs': { zh: '本地操作契约与输入验证', en: 'local operation contracts and input validation' },
|
|
259
|
+
'local-contract-types.mjs': { zh: '共享执行数据契约', en: 'shared execution data contracts' },
|
|
71
260
|
'local-state-lock.mjs': { zh: '本地状态并发锁', en: 'local state concurrency lock' },
|
|
72
261
|
'local-execution.mjs': { zh: '本地执行闸门与预算', en: 'local execution gates and budgets' },
|
|
73
262
|
'local-integrity.mjs': { zh: '证据与回执验签', en: 'evidence and receipt verification' },
|
|
263
|
+
'local-evidence-verification.mjs': { zh: 'Validator 独立证据验证与执行结果绑定', en: 'Validator independent evidence verification and execution result binding' },
|
|
74
264
|
'local-formula.mjs': { zh: '确定性公式引擎', en: 'deterministic formula engine' },
|
|
75
265
|
'local-ledger.mjs': { zh: '执行与链路台账', en: 'execution and chain ledger' },
|
|
76
266
|
'local-approved-plan.mjs': { zh: '冻结计划执行器', en: 'frozen plan runner' },
|
|
77
267
|
'local-budget-renewal.mjs': { zh: '预算续期确认', en: 'budget renewal confirmation' },
|
|
268
|
+
'local-budget-grants.mjs': { zh: '预算签名授权与原任务绑定', en: 'signed budget grants and original task binding' },
|
|
269
|
+
'local-budget-handoff.mjs': { zh: '交接读取权限与连续预算恢复', en: 'handoff read authority and continuous budget restoration' },
|
|
270
|
+
'local-budget-handoff-completion.mjs': { zh: '交接完成证明与读取授权', en: 'handoff completion proof and read authority' },
|
|
271
|
+
'local-budget-handoff-contracts.mjs': { zh: '交接预算输入契约', en: 'handoff budget input contracts' },
|
|
272
|
+
'local-budget-lock.mjs': { zh: '预算并发锁与崩溃恢复', en: 'budget concurrency lock and crash recovery' },
|
|
273
|
+
'local-budget-reads.mjs': { zh: '预算读取上下文与受控适配', en: 'budget read context and controlled adapters' },
|
|
274
|
+
'local-budget-source-bindings.mjs': { zh: '源文件与快照缓存路径绑定', en: 'source and snapshot cache path binding' },
|
|
275
|
+
'local-budget-store.mjs': { zh: '预算追加台账和完整性校验', en: 'budget append-only journal and integrity checks' },
|
|
276
|
+
'local-budget-transition.mjs': { zh: '候选范围与正式范围预算转换', en: 'candidate and accepted scope budget transition' },
|
|
277
|
+
'local-budget.mjs': { zh: '本地三轴读取预算', en: 'local three-axis read budgets' },
|
|
78
278
|
'local-probe.mjs': { zh: '范围探测与分档', en: 'scope probing and tiering' },
|
|
279
|
+
'local-scope-candidate.mjs': { zh: '临时接管范围独立验签', en: 'temporary takeover scope verification' },
|
|
280
|
+
'local-scope-context.mjs': { zh: '精确符号范围绑定', en: 'exact symbol scope binding' },
|
|
281
|
+
'local-scope-files.mjs': { zh: '范围文件与安全读取', en: 'scope files and guarded reads' },
|
|
282
|
+
'local-scope-repository.mjs': { zh: '真实仓库范围事实', en: 'actual repository scope facts' },
|
|
283
|
+
'local-scope-git.mjs': { zh: '实际Git范围与变更事实', en: 'actual Git scope and change facts' },
|
|
284
|
+
'local-scope-git-reads.mjs': { zh: '固定Git元数据与源码读取', en: 'fixed Git metadata and source reads' },
|
|
285
|
+
'local-scope-git-comparison.mjs': { zh: 'Git范围比较接线', en: 'Git scope comparison wiring' },
|
|
286
|
+
'local-scope-git-attributes.mjs': { zh: 'Git属性读取与语义保留', en: 'Git attribute reads and semantics' },
|
|
287
|
+
'local-scope-git-history.mjs': { zh: '实际Git历史变更统计', en: 'actual Git history change statistics' },
|
|
288
|
+
'local-budget-git.mjs': { zh: 'Git源码读取预算', en: 'Git source read budgets' },
|
|
289
|
+
'local-budget-git-loader.mjs': { zh: '固定Git源码加载与校验', en: 'fixed Git source loading and validation' },
|
|
290
|
+
'local-budget-git-scratch.mjs': { zh: 'Git比较副本读取预算', en: 'Git comparison copy read budgets' },
|
|
291
|
+
'local-budget-git-scratch-loader.mjs': { zh: '固定Git比较副本与执行', en: 'fixed Git comparison copies and execution' },
|
|
292
|
+
'local-scope-signature.mjs': { zh: '新鲜范围回执签名', en: 'fresh scope receipt signing' },
|
|
293
|
+
'local-scope-snapshot.mjs': { zh: '范围快照与原副本校验', en: 'scope snapshots and original copy validation' },
|
|
294
|
+
'local-scope-state.mjs': { zh: '原范围历史与逐级重估', en: 'original scope history and incremental reassessment' },
|
|
295
|
+
'local-scope-workspaces.mjs': { zh: '实际workspace元数据', en: 'actual workspace metadata' },
|
|
79
296
|
'local-task-routing.mjs': { zh: '本地任务路由', en: 'local task routing' },
|
|
297
|
+
'local-task-handoff-fence.mjs': { zh: '任务安全交接与撤权', en: 'task safe handoff and revocation' },
|
|
298
|
+
'local-task-handoff-storage.mjs': { zh: '任务交接可信存储', en: 'task handoff trusted storage' },
|
|
299
|
+
'local-task-handoff-overlay-wire.mjs': { zh: '任务接管范围凭据', en: 'task takeover scope receipts' },
|
|
300
|
+
'local-task-handoff-completion-wire.mjs': { zh: '任务接管完成凭据', en: 'task takeover completion receipts' },
|
|
301
|
+
'local-task-handoff-contracts.mjs': { zh: '任务交接本地调用契约', en: 'task handoff local invocation contracts' },
|
|
302
|
+
'local-task-handoff-write-constraints.mjs': { zh: '接管继承范围与架构约束', en: 'takeover inherited scope and architecture constraints' },
|
|
303
|
+
'local-task-handoff-observation.mjs': { zh: '接管受信本地观察', en: 'trusted local handoff observation' },
|
|
304
|
+
'local-task-handoff-read-authority.mjs': { zh: '临时读取授权与原目录绑定', en: 'temporary read authority and original home binding' },
|
|
305
|
+
'local-task-handoff-write-wire.mjs': { zh: '接管写入凭证契约', en: 'handoff write receipt contracts' },
|
|
306
|
+
'local-task-handoff-write-archive.mjs': { zh: '接管完整写入历史', en: 'complete handoff write history' },
|
|
307
|
+
'local-task-handoff-write-receipts.mjs': { zh: '接管实际写入凭证', en: 'actual handoff write receipts' },
|
|
308
|
+
'workflow-local-runner.mjs': { zh: '工作流原租约业务执行', en: 'workflow original lease business execution' },
|
|
309
|
+
'workflow-local-contracts.mjs': { zh: '工作流本地调用契约', en: 'workflow local invocation contracts' },
|
|
310
|
+
'workflow-local-client.mjs': { zh: '工作流真实执行授权', en: 'workflow actual execution authorization' },
|
|
311
|
+
'workflow-local-request.mjs': { zh: '工作流原执行请求恢复', en: 'workflow original execution request recovery' },
|
|
80
312
|
'remote-client.mjs': { zh: '远端恢复客户端', en: 'remote recovery client' },
|
|
81
|
-
|
|
313
|
+
'task-message-entry.mjs': { zh: '任务消息实际投递入口', en: 'task message host delivery entry' },
|
|
314
|
+
'task-message-cli.mjs': { zh: '任务消息命令与适配器', en: 'task message command and adapter' },
|
|
315
|
+
})
|
|
82
316
|
return {
|
|
83
317
|
zh: `更新了${changed.map(name => labels[name].zh).join('、')}。`,
|
|
84
318
|
en: `Updated ${changed.map(name => labels[name].en).join(', ')}.`,
|
package/releases.json
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.1.24",
|
|
4
|
+
"date": "2026-10-07",
|
|
5
|
+
"zh": "更新已验收能力并完成发布前校验。",
|
|
6
|
+
"en": "Updated accepted capabilities and completed release preflight validation."
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"version": "0.1.23",
|
|
10
|
+
"date": "2026-10-06",
|
|
11
|
+
"zh": "修复受管安装漏装能力映射文档的问题;旧安装自动补齐,用户编辑仍受保护。",
|
|
12
|
+
"en": "Fixed the missing capability map in managed installations; older installations are repaired while user edits remain protected."
|
|
13
|
+
},
|
|
2
14
|
{
|
|
3
15
|
"version": "0.1.22",
|
|
4
16
|
"date": "2026-10-04",
|
package/remote-client.mjs
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
+
import Ajv from 'ajv';
|
|
3
|
+
import { parseTransportResponse, requestTransport, trustedOrigin } from './remote-transport.mjs';
|
|
4
|
+
import { appendInvocation } from './local-invocations.mjs';
|
|
2
5
|
|
|
3
6
|
export const apiUrl = 'https://entrorove.com/api/skill/invoke';
|
|
4
7
|
|
|
@@ -15,33 +18,28 @@ function requestId(operation, input) {
|
|
|
15
18
|
}
|
|
16
19
|
|
|
17
20
|
export function buildInvocation(operation, input) {
|
|
18
|
-
if (!['capabilities', 'task-describe', 'message-route', 'message-accept', 'task-resume', '
|
|
21
|
+
if (!['capabilities', 'task-describe', 'message-route', 'message-accept', 'task-resume', 'task-checkpoint',
|
|
22
|
+
'message-status', 'message-delivery-start', 'message-delivery-report', 'message-resolve', 'message-complete',
|
|
23
|
+
'handoff-prepare', 'handoff-release', 'handoff-claim', 'handoff-status', 'handoff-resume', 'handoff-execution-authority', 'mutation-snapshot-challenge', 'mutation-pass-issue',
|
|
24
|
+
'start', 'continue'].includes(operation)) throw new Error('Invalid entrorove operation');
|
|
19
25
|
if (!input || typeof input !== 'object' || Array.isArray(input)) throw new Error('Input must be a JSON object');
|
|
20
26
|
const id = requestId(operation, input);
|
|
21
27
|
return { url: apiUrl, requestId: id, body: { schemaVersion: 'entrorove.skill.request/2.0', requestId: id, operation, input } };
|
|
22
28
|
}
|
|
23
29
|
|
|
24
|
-
|
|
25
|
-
|
|
30
|
+
export function validateDiscoveredChecks(input, checks = []) {
|
|
31
|
+
for (const check of checks) {
|
|
32
|
+
if (check.kind !== 'unique-property' || typeof check.path !== 'string' || typeof check.property !== 'string') throw new Error('Unsupported capability input check');
|
|
33
|
+
const value = check.path.split('.').reduce((current, key) => current?.[key], input);
|
|
34
|
+
if (value === undefined) continue;
|
|
35
|
+
if (!Array.isArray(value) || new Set(value.map(item => item?.[check.property])).size !== value.length) throw new Error(`Invalid input: ${check.path} requires unique ${check.property} values`);
|
|
36
|
+
}
|
|
26
37
|
}
|
|
27
38
|
|
|
28
|
-
function
|
|
29
|
-
const code = error?.cause?.code ?? error?.code;
|
|
30
|
-
return ['ECONNRESET', 'ECONNREFUSED', 'EAI_AGAIN', 'ENETUNREACH', 'ENETDOWN',
|
|
31
|
-
'EHOSTUNREACH', 'ETIMEDOUT', 'ECONNABORTED', 'UND_ERR_CONNECT_TIMEOUT'].includes(code);
|
|
32
|
-
}
|
|
39
|
+
async function readResponse(response, label) { return parseTransportResponse(response, label); }
|
|
33
40
|
|
|
34
|
-
async function readOnlyGet(
|
|
35
|
-
|
|
36
|
-
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
37
|
-
try {
|
|
38
|
-
return await fetch(url, { method: 'GET', redirect: 'error', signal: AbortSignal.timeout(15_000), headers });
|
|
39
|
-
} catch (error) {
|
|
40
|
-
last = error;
|
|
41
|
-
if (!preTlsRetryable(error) || attempt === 2) break;
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
throw new Error(`Unable to read ${label}; ${last instanceof Error ? last.message : 'network error'}`);
|
|
41
|
+
async function readOnlyGet(origin, pathname, headers) {
|
|
42
|
+
return requestTransport(origin, pathname, { headers });
|
|
45
43
|
}
|
|
46
44
|
|
|
47
45
|
export async function invokeRemote(data, dependencies) {
|
|
@@ -52,39 +50,132 @@ export async function invokeRemote(data, dependencies) {
|
|
|
52
50
|
process.exitCode = 2;
|
|
53
51
|
return;
|
|
54
52
|
}
|
|
55
|
-
const call = buildInvocation(data.operation, data.input);
|
|
53
|
+
const call = { ...buildInvocation(data.operation, data.input), url: `${trustedOrigin(apiOrigin())}/api/skill/invoke` };
|
|
56
54
|
const token = await readCredential(home);
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
response
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
const result = await readResponse(response, 'invocation');
|
|
68
|
-
if (!result || !result.output || result.output.requestId !== call.requestId) {
|
|
69
|
-
throw new Error(`Invalid entrorove response; requestId=${call.requestId}`);
|
|
55
|
+
if (data.operation !== 'capabilities') {
|
|
56
|
+
const discovery = await postInvocation({ ...buildInvocation('capabilities', {}), url: call.url }, token, home);
|
|
57
|
+
if (!discovery.response.ok || discovery.result.output.status !== 'succeeded') throw new Error(`Capability discovery failed: HTTP ${discovery.response.status}`);
|
|
58
|
+
const capabilities = discovery.result.output.capabilities;
|
|
59
|
+
const schema = capabilities?.operationSchemas?.[data.operation];
|
|
60
|
+
if (!capabilities?.operations?.includes(data.operation) || !schema) throw new Error(`Capability discovery does not support ${data.operation}`);
|
|
61
|
+
const validate = new Ajv({ strict: true, strictRequired: false, allErrors: true }).compile(schema);
|
|
62
|
+
if (!validate(data.input)) throw new Error(`Invalid ${data.operation} input: ${validate.errors.map(error => `${error.instancePath || '/'} ${error.message}`).join('; ')}`);
|
|
63
|
+
validateDiscoveredChecks(data.input, capabilities.inputChecks?.[data.operation]);
|
|
70
64
|
}
|
|
65
|
+
const { response, result } = await postInvocation(call, token, home);
|
|
71
66
|
process.stdout.write(JSON.stringify(result) + '\n');
|
|
72
67
|
if (!response.ok || result.output.status === 'blocked' || result.output.status === 'failed'
|
|
73
68
|
|| result.output.status === 'incomplete') process.exitCode = 2;
|
|
74
69
|
}
|
|
75
70
|
|
|
71
|
+
async function postInvocation(call, token, home) {
|
|
72
|
+
const metadata = { kind: 'remote', operation: call.body.operation, requestId: call.requestId };
|
|
73
|
+
const logged = async value => {
|
|
74
|
+
try { return await appendInvocation({ ...metadata, ...value }, home); }
|
|
75
|
+
catch { throw unknownInvocation(call.requestId); }
|
|
76
|
+
};
|
|
77
|
+
await appendInvocation({ ...metadata, event: 'started' }, home);
|
|
78
|
+
let response; let result;
|
|
79
|
+
try {
|
|
80
|
+
response = await requestTransport(new URL(call.url).origin, '/api/skill/invoke', {
|
|
81
|
+
method: 'POST', timeoutMs: 135_000,
|
|
82
|
+
headers: { 'content-type': 'application/json', authorization: `Bearer ${token}` }, body: JSON.stringify(call.body),
|
|
83
|
+
});
|
|
84
|
+
} catch (cause) {
|
|
85
|
+
if (cause.established) await logged({ event: 'outcome-unknown' });
|
|
86
|
+
else await appendInvocation({ ...metadata, event: 'not-sent' }, home);
|
|
87
|
+
if (cause.established) throw unknownInvocation(call.requestId);
|
|
88
|
+
throw Object.assign(new Error(`Entrorove request was not sent; connection failed after ${cause.attempts ?? 1} attempt(s); requestId=${call.requestId}`),
|
|
89
|
+
{ requestId: call.requestId, retryableBeforeTransmission: Boolean(cause.retryableBeforeTransmission), attempts: cause.attempts ?? 1 });
|
|
90
|
+
}
|
|
91
|
+
try { result = await readResponse(response, 'invocation'); } catch {
|
|
92
|
+
await logged({ event: 'outcome-unknown' }); throw unknownInvocation(call.requestId);
|
|
93
|
+
}
|
|
94
|
+
if (!response.ok && !result?.output) {
|
|
95
|
+
await logged({ event: response.status >= 500 ? 'outcome-unknown' : 'rejected' });
|
|
96
|
+
if (response.status >= 500) throw unknownInvocation(call.requestId);
|
|
97
|
+
const code = typeof result?.error === 'string' && /^[a-z][a-z0-9-]{0,63}$/.test(result.error) ? result.error : 'request-rejected';
|
|
98
|
+
throw new Error(`entrorove invocation failed: HTTP ${response.status}; ${code}; requestId=${call.requestId}`);
|
|
99
|
+
}
|
|
100
|
+
if (!result?.output || result.output.requestId !== call.requestId) {
|
|
101
|
+
await logged({ event: 'outcome-unknown' }); throw unknownInvocation(call.requestId);
|
|
102
|
+
}
|
|
103
|
+
await logged({ event: response.ok ? 'completed' : 'rejected', usage: result.usage ?? [] });
|
|
104
|
+
return { response, result };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
function unknownInvocation(requestId) {
|
|
108
|
+
return Object.assign(new Error(`Invocation outcome is unknown; requestId=${requestId}. Do not automatically resend this request.`),
|
|
109
|
+
{ requestId, outcomeUnknown: true });
|
|
110
|
+
}
|
|
111
|
+
async function machineCredential(dependencies) {
|
|
112
|
+
await dependencies.install();
|
|
113
|
+
if (!await dependencies.agreementAccepted(dependencies.home)) {
|
|
114
|
+
throw Object.assign(new Error('Entrorove agreement requires explicit acceptance before task message communication'),
|
|
115
|
+
{ interaction: dependencies.agreementRequired(dependencies.home) });
|
|
116
|
+
}
|
|
117
|
+
return dependencies.readCredential(dependencies.home);
|
|
118
|
+
}
|
|
119
|
+
function machineOrigin(dependencies) { return trustedOrigin(dependencies.apiOrigin()); }
|
|
120
|
+
function validateMachineCapability(operation, input, capabilities) {
|
|
121
|
+
const schema = capabilities?.operationSchemas?.[operation];
|
|
122
|
+
if (!capabilities?.operations?.includes(operation) || !schema) throw new Error(`Capability discovery does not support ${operation}`);
|
|
123
|
+
const validate = new Ajv({ strict: true, strictRequired: false, allErrors: true }).compile(schema);
|
|
124
|
+
if (!validate(input)) throw new Error(`Invalid ${operation} input: ${validate.errors.map(error => `${error.instancePath || '/'} ${error.message}`).join('; ')}`);
|
|
125
|
+
validateDiscoveredChecks(input, capabilities.inputChecks?.[operation]);
|
|
126
|
+
}
|
|
127
|
+
function stoppedOriginalResume(response, output, operation, input) {
|
|
128
|
+
return operation === 'task-resume' && response.status === 422 && output?.schemaVersion === 'entrorove.skill.response/1.0'
|
|
129
|
+
&& output.status === 'blocked' && output.canContinue === false && typeof output.task?.taskId === 'string'
|
|
130
|
+
&& Boolean(input.taskId || input.flowId) && (!input.taskId || output.task.taskId === input.taskId)
|
|
131
|
+
&& (!input.flowId || output.task.flowId === input.flowId && output.flowId === input.flowId);
|
|
132
|
+
}
|
|
133
|
+
export function createTaskMessageClient(dependencies) {
|
|
134
|
+
if (!dependencies || !['install', 'agreementAccepted', 'agreementRequired', 'readCredential', 'apiOrigin']
|
|
135
|
+
.every(key => typeof dependencies[key] === 'function')) throw new Error('Task message client requires its installed credential and agreement dependencies');
|
|
136
|
+
return {
|
|
137
|
+
async invoke(operation, input) {
|
|
138
|
+
const original = buildInvocation(operation, input);
|
|
139
|
+
const token = await machineCredential(dependencies); const origin = machineOrigin(dependencies);
|
|
140
|
+
if (operation !== 'capabilities') {
|
|
141
|
+
const discovery = buildInvocation('capabilities', {});
|
|
142
|
+
const discovered = await postInvocation({ ...discovery, url: `${origin}/api/skill/invoke` }, token, dependencies.home);
|
|
143
|
+
if (!discovered.response.ok || discovered.result.output.status !== 'succeeded') throw new Error('Task message capability discovery failed');
|
|
144
|
+
validateMachineCapability(operation, input, discovered.result.output.capabilities);
|
|
145
|
+
}
|
|
146
|
+
const { response, result } = await postInvocation({ ...original, url: `${origin}/api/skill/invoke` }, token, dependencies.home);
|
|
147
|
+
if (stoppedOriginalResume(response, result.output, operation, input)) return result.output;
|
|
148
|
+
if (!response.ok || ['blocked', 'failed', 'incomplete'].includes(result.output.status)) {
|
|
149
|
+
throw new Error(`Task message invocation was rejected: HTTP ${response.status}; requestId=${original.requestId}`);
|
|
150
|
+
}
|
|
151
|
+
return result.output;
|
|
152
|
+
},
|
|
153
|
+
async status(id) {
|
|
154
|
+
if (typeof id !== 'string' || !/^[a-f0-9]{64}$/.test(id)) throw new Error('Task message status requires its original sha256 requestId');
|
|
155
|
+
const token = await machineCredential(dependencies);
|
|
156
|
+
const response = await readOnlyGet(machineOrigin(dependencies), `/api/skill/status/${id}`,
|
|
157
|
+
{ authorization: `Bearer ${token}` }, 'original task message status');
|
|
158
|
+
const result = await readResponse(response, 'task message status');
|
|
159
|
+
if (!response.ok || !result?.output || result.output.requestId !== id) throw new Error('Original task message status is unavailable or invalid');
|
|
160
|
+
await appendInvocation({ kind: 'remote', operation: 'status', requestId: id, event: 'status', usage: result.usage ?? [] }, dependencies.home);
|
|
161
|
+
return result.output;
|
|
162
|
+
},
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
76
166
|
export async function queryStatus(requestId, dependencies) {
|
|
77
167
|
if (typeof requestId !== 'string' || !/^[a-f0-9]{64}$/.test(requestId)) throw new Error('status requires a sha256 requestId');
|
|
78
168
|
const token = await dependencies.readCredential(dependencies.home);
|
|
79
|
-
const response = await readOnlyGet(
|
|
169
|
+
const response = await readOnlyGet(dependencies.apiOrigin(), `/api/skill/status/${encodeURIComponent(requestId)}`, { authorization: `Bearer ${token}` }, 'status')
|
|
80
170
|
const result = await readResponse(response, 'status');
|
|
81
|
-
if (!response.ok) throw new Error(`entrorove status failed: HTTP ${response.status}; requestId=${requestId}`);
|
|
171
|
+
if (!response.ok || result?.output?.requestId !== requestId) throw new Error(`entrorove status failed: HTTP ${response.status}; requestId=${requestId}`);
|
|
172
|
+
await appendInvocation({ kind: 'remote', operation: 'status', requestId, event: 'status', usage: result.usage ?? [] }, dependencies.home);
|
|
82
173
|
process.stdout.write(JSON.stringify(result) + '\n');
|
|
83
174
|
}
|
|
84
175
|
|
|
85
176
|
export async function queryFlows(dependencies) {
|
|
86
177
|
const token = await dependencies.readCredential(dependencies.home);
|
|
87
|
-
const response = await readOnlyGet(
|
|
178
|
+
const response = await readOnlyGet(dependencies.apiOrigin(), '/api/skill/flows', { authorization: `Bearer ${token}` }, 'flow list')
|
|
88
179
|
const result = await readResponse(response, 'flow list');
|
|
89
180
|
if (!response.ok) throw new Error(`entrorove flow list failed: HTTP ${response.status}`);
|
|
90
181
|
process.stdout.write(JSON.stringify(result) + '\n');
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import http from 'node:http';
|
|
2
|
+
import https from 'node:https';
|
|
3
|
+
|
|
4
|
+
const PRE_CONNECT = new Set(['ECONNREFUSED', 'ECONNRESET', 'EAI_AGAIN', 'ENOTFOUND', 'ENETUNREACH',
|
|
5
|
+
'ENETDOWN', 'EHOSTUNREACH', 'ETIMEDOUT', 'ECONNABORTED']);
|
|
6
|
+
const MAX_BYTES = 1_048_576;
|
|
7
|
+
|
|
8
|
+
export function trustedOrigin(value) {
|
|
9
|
+
let url;
|
|
10
|
+
try { url = new URL(value); } catch { throw new Error('Invalid Entrorove API origin'); }
|
|
11
|
+
if (url.username || url.password || url.search || url.hash || url.pathname !== '/'
|
|
12
|
+
|| url.protocol !== 'https:' && !(url.protocol === 'http:' && ['127.0.0.1', 'localhost', '[::1]'].includes(url.hostname))) {
|
|
13
|
+
throw new Error('Entrorove API requires HTTPS or an owned loopback listener');
|
|
14
|
+
}
|
|
15
|
+
return url.origin;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function failure(code, established) {
|
|
19
|
+
return Object.assign(new Error(established ? 'Entrorove response was interrupted after connection establishment'
|
|
20
|
+
: 'Entrorove connection failed before request transmission'), {
|
|
21
|
+
code: 'ENTROROVE_TRANSPORT', established, retryableBeforeTransmission: !established && PRE_CONNECT.has(code),
|
|
22
|
+
transportCode: PRE_CONNECT.has(code) ? code : 'CONNECTION_REJECTED',
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async function attempt(url, options) {
|
|
27
|
+
return new Promise((resolve, reject) => {
|
|
28
|
+
let established = false; let settled = false;
|
|
29
|
+
const done = (cause, result) => {
|
|
30
|
+
if (settled) return; settled = true; clearTimeout(timer);
|
|
31
|
+
if (cause) reject(failure(cause.code, established)); else resolve(result);
|
|
32
|
+
};
|
|
33
|
+
const client = url.protocol === 'https:' ? https : http;
|
|
34
|
+
const request = client.request(url, { method: options.method, headers: options.headers,
|
|
35
|
+
agent: false }, response => {
|
|
36
|
+
established = true; const chunks = []; let size = 0;
|
|
37
|
+
response.on('data', chunk => {
|
|
38
|
+
size += chunk.length;
|
|
39
|
+
if (size > MAX_BYTES) { done({ code: 'RESPONSE_TOO_LARGE' }); response.destroy(); request.destroy(); }
|
|
40
|
+
else chunks.push(chunk);
|
|
41
|
+
});
|
|
42
|
+
response.on('aborted', () => done({ code: 'RESPONSE_INTERRUPTED' }));
|
|
43
|
+
response.on('error', cause => done(cause));
|
|
44
|
+
response.on('end', () => done(null, { ok: response.statusCode >= 200 && response.statusCode < 300,
|
|
45
|
+
status: response.statusCode, headers: response.headers, body: Buffer.concat(chunks).toString('utf8') }));
|
|
46
|
+
});
|
|
47
|
+
request.on('socket', socket => {
|
|
48
|
+
socket.once(url.protocol === 'https:' ? 'secureConnect' : 'connect', () => { established = true; });
|
|
49
|
+
});
|
|
50
|
+
request.on('error', cause => done(cause));
|
|
51
|
+
const timer = setTimeout(() => { done({ code: 'ETIMEDOUT' }); request.destroy(); }, options.timeoutMs);
|
|
52
|
+
request.end(options.body);
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function requestTransport(origin, pathname, options = {}) {
|
|
57
|
+
const trusted = trustedOrigin(origin);
|
|
58
|
+
if (typeof pathname !== 'string' || !pathname.startsWith('/api/') || pathname.includes('://')) throw new Error('Invalid Entrorove API path');
|
|
59
|
+
const url = new URL(pathname, trusted);
|
|
60
|
+
if (url.origin !== trusted || url.search || url.hash) throw new Error('Invalid Entrorove API path');
|
|
61
|
+
const configured = { timeoutMs: 15_000, method: 'GET', ...options };
|
|
62
|
+
if (!['GET', 'POST'].includes(configured.method)) throw new Error('Invalid Entrorove transport method');
|
|
63
|
+
for (let number = 1; number <= 3; number++) {
|
|
64
|
+
try {
|
|
65
|
+
const response = await attempt(url, configured);
|
|
66
|
+
if (response.status >= 300 && response.status < 400) {
|
|
67
|
+
throw Object.assign(new Error('Entrorove API redirects are refused'), { code: 'ENTROROVE_REDIRECT', established: true });
|
|
68
|
+
}
|
|
69
|
+
return { ...response, attempts: number };
|
|
70
|
+
} catch (cause) {
|
|
71
|
+
cause.attempts = number;
|
|
72
|
+
if (!cause.retryableBeforeTransmission || number === 3) throw cause;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export function parseTransportResponse(response, label = 'Entrorove') {
|
|
78
|
+
try { return JSON.parse(response.body); }
|
|
79
|
+
catch { throw Object.assign(new Error(`Invalid ${label} response`), { code: 'ENTROROVE_RESPONSE_INVALID' }); }
|
|
80
|
+
}
|