@entrorove/skill 0.1.68 → 0.1.70
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/CAPABILITY-MAP.md +2 -0
- package/CHANGELOG.md +10 -0
- package/IDE-EXECUTION.md +16 -2
- package/SKILL.md +3 -2
- package/cli.mjs +1 -1
- package/cloud-locale.d.mts +7 -0
- package/cloud-locale.mjs +59 -0
- package/cloud-task-client.mjs +21 -13
- package/cloud-watch-client.mjs +11 -3
- package/connected-cli.mjs +2 -0
- package/design-lint.mjs +20 -2
- package/ide-command.mjs +1 -1
- package/ide-hook.mjs +4 -4
- package/ide-presentation.mjs +15 -4
- package/local-archguard-components.mjs +31 -4
- package/local-contracts.mjs +5 -2
- package/local-delegated-modify-analysis.mjs +16 -7
- package/local-discipline-gate.mjs +2 -0
- package/local-discipline-snapshot.mjs +8 -2
- package/local-mutation-snapshot.mjs +2 -2
- package/local-preserved-mutation-protection.mjs +2 -0
- package/local-scope-files.mjs +14 -2
- package/local-scope-read-set.mjs +66 -0
- package/local-scope-repository.mjs +97 -13
- package/local-scope-signature.mjs +52 -6
- package/local-scope-uni-build.mjs +135 -0
- package/local-scope-uni-conditional.mjs +54 -0
- package/local-scope-uni-directives.mjs +96 -0
- package/local-scope-uni-expressions.mjs +101 -0
- package/local-scope-workspaces.mjs +14 -2
- package/manifest.json +1 -1
- package/mutation-client.mjs +8 -5
- package/package.json +17 -2
- package/release-state.json +46 -31
- package/release.mjs +4 -3
- package/releases.json +12 -0
- package/remote-client.mjs +1 -0
- package/scope-amendment-observer.mjs +3 -1
- package/scope-amendment-state.mjs +3 -1
- package/scope-context-client.mjs +118 -0
- package/scope-context-journal.mjs +44 -0
- package/scope-context-observation.mjs +42 -0
- package/scope-context-observer.mjs +86 -0
- package/scope-context-release.mjs +8 -0
- package/scope-context-remote.mjs +60 -0
- package/scope-context-state.mjs +88 -0
- package/scope-context-wire.mjs +84 -0
- package/scope-runner-client.mjs +9 -5
package/release-state.json
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "entrorove.release-state/1.0",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"digest": "
|
|
3
|
+
"version": "0.1.70",
|
|
4
|
+
"digest": "888f8c2a60595e87e39b9423f811a0e231ec5309094f3de0d88cb3f729371ba8",
|
|
5
5
|
"files": {
|
|
6
|
+
"scope-context-client.mjs": "dbfec7db0e118f3025a0e45475f3328a171e4cd1dd86e6c8d326d779ce61b459",
|
|
7
|
+
"scope-context-observer.mjs": "9d041db8de6e45113ee04b189c9d52097ec902a104721829dd382cf6daf5d1ce",
|
|
8
|
+
"scope-context-observation.mjs": "d92f2fca3c923caa6f0c5c9cc60b4f12bdae212071da64da6692e3e99b251969",
|
|
9
|
+
"scope-context-remote.mjs": "b52cdee03e845edc15eae6bb3ccfaea9c4482c03f2fae7001439e4abcb2acd33",
|
|
10
|
+
"scope-context-state.mjs": "7bc434620bfc505ee290f1977e64ef22e50f72665d75e7dfd6805deab4e81826",
|
|
11
|
+
"scope-context-wire.mjs": "a15d0b966615b8293e53e4229edc8fb444fb144cc336dbd6354ac995f33e8cc8",
|
|
12
|
+
"scope-context-journal.mjs": "753821f546e36185b2e891e8f38758a2d15a591f700f0650d478892c8d958a45",
|
|
13
|
+
"scope-context-release.mjs": "3b6f5d3bf7abe25e1a1edd0521053f4c1b1e3487b7f37d5f7c6080d32bc0c044",
|
|
14
|
+
"cloud-locale.mjs": "0627ac75b98b439563b61ab217aacb55a099c1d0c8ed3b118776d2007c52dd70",
|
|
15
|
+
"cloud-locale.d.mts": "aff4bced9bbac140f73fd0de24681287349389be5750d89d96abe0f8a2167664",
|
|
6
16
|
"cloud-task-images.mjs": "a260a94b6b1b47df97a8cc8657dfdce1fd37ec752f1cc2bad2542eaa28622bdb",
|
|
7
17
|
"model-images.mjs": "ab85ac0c44d857c1f460de3e9c06eb1d37b57688b4a6061405c0a44ae4d40bd7",
|
|
8
18
|
"model-images.d.mts": "f1506cfb8ad287869f92f4d9074c7c759c6c28b182aeb325dd5f22a38926f24c",
|
|
@@ -19,7 +29,7 @@
|
|
|
19
29
|
"local-mutation-finder-observation.mjs": "438dd33e62e03e02b55897a28b3ba59d12734b6e5142525b299f77c21537280b",
|
|
20
30
|
"local-finder-store.mjs": "227191c52174386ace6391e072b78a6e4cc658a6d9dd37036ffd7e97bbf4336a",
|
|
21
31
|
"local-finder-plist.mjs": "c83ddab2375a54d612d395a5518db8ae05212437d82bf3f8b76930a8859c8481",
|
|
22
|
-
"connected-cli.mjs": "
|
|
32
|
+
"connected-cli.mjs": "29ab700f6a308adad5f3984bf9dd2734755a29fbd0e963e630222565846b5942",
|
|
23
33
|
"local-approved-process.mjs": "442856df788e63f38757439ba0657d1c689aaf797631a955fae3dd639e844e6d",
|
|
24
34
|
"local-approved-supervisor.mjs": "87142a4c13d27c8265cc1fd7fc9088988da9bbb02134164e1a7c5417da926ac7",
|
|
25
35
|
"local-mutation-consumption.mjs": "1b033655f817ec576410b7f91f1640b8651f3cff0668154fb8e6e14e7b31d8f4",
|
|
@@ -30,16 +40,16 @@
|
|
|
30
40
|
"workflow-observation-runner.mjs": "3eb8280ec7abffcb30398e3f4e5f7d0ec3df4385fa720f188ed83757b87cd977",
|
|
31
41
|
"workflow-observation-state.mjs": "a525046df9b3de75b10d2bf35c2b6d7719f12a647e4aee1f1e85dbdbfb167321",
|
|
32
42
|
"workflow-observation-wire.mjs": "df0d5e4f8fde0be8bf06c6c4590cd158b4da05ebe6ef3169d2366db706f3327f",
|
|
33
|
-
"local-preserved-mutation-protection.mjs": "
|
|
43
|
+
"local-preserved-mutation-protection.mjs": "289bf58933818ff13b217d0d75afd0b81cc59bc09b4ea88f50a2ab900e9cf1c2",
|
|
34
44
|
"local-preserved-mutation-signer.mjs": "2b0771cbdd18ba00267aa441b7892cd04feab9f8543ae5e2703430b1e580747f",
|
|
35
45
|
"local-preserved-mutation-state.mjs": "337a172b2d0a03b0d5a89b8483afdd9a043a4999fe38f87679633c98c450126b",
|
|
36
46
|
"local-preserved-mutation-wire.mjs": "6768ce5713d70f7c0bd05f2286bc4b32cd9b8bb1d3c8b9cc7a451cb9b176824d",
|
|
37
|
-
"local-delegated-modify-analysis.mjs": "
|
|
38
|
-
"mutation-client.mjs": "
|
|
47
|
+
"local-delegated-modify-analysis.mjs": "f8769bd9890a041be48db5cb6724873d59300c102a5ddaf0a937e5e4f3f1983a",
|
|
48
|
+
"mutation-client.mjs": "8f1066db3246f7639dd0b557e7b2c6175181e52f9087146e218d0912f791808e",
|
|
39
49
|
"cloud-mutation-authority.mjs": "c7226e882a4f3be4d2f55728f515d5a815c0aa1f21aa5e4689314e6e6a8c66a2",
|
|
40
50
|
"ide-code-mode.mjs": "f8ba4de33632ab4c6df52dab52f392414b4632c7e94b218b8065677970c075c7",
|
|
41
|
-
"ide-command.mjs": "
|
|
42
|
-
"ide-hook.mjs": "
|
|
51
|
+
"ide-command.mjs": "b3c008816f53e3cd3aa97bc792baf0b7fc068e839b150bd2cfc6cb06d17a6825",
|
|
52
|
+
"ide-hook.mjs": "688e39193575e20f833a4f9e8f0975351d03869452acd46c8860e86ce05bccdc",
|
|
43
53
|
"ide-install.mjs": "1c80e191ddc2ac8789f0c71edc7bc8c3c8cea6bfab537cdf6baffa4a6ce3419c",
|
|
44
54
|
"ide-session.mjs": "5277a6ea3445bfa9b2e28847372d963da77787d472d0414c0e253d4fe29f74ec",
|
|
45
55
|
"break-glass.mjs": "6ec9f97c5d68bb33121b2374c06b9d4c8eb3419b52d00849fec7124bc63e4582",
|
|
@@ -53,11 +63,11 @@
|
|
|
53
63
|
"local-scope-import-expressions.mjs": "20f1e065582c68d2334e0dfaa130a559ff19886a57f9038dc569f65993bb06c8",
|
|
54
64
|
"local-discipline-contracts.mjs": "25d2bdbcb2698a1927ce5ef43e33052ed90bfe7dbc7c6a708f2bfd4a258609fd",
|
|
55
65
|
"local-discipline-contracts.d.mts": "defc684c78dc88afa1c54340ab4a01ae36db7aa11257cbe1f5cd323f608c78c4",
|
|
56
|
-
"local-discipline-gate.mjs": "
|
|
66
|
+
"local-discipline-gate.mjs": "f80c560a4eb7c153e1637d072f0a6b4e13d4caba745317a01ff7f9b5e9143f69",
|
|
57
67
|
"local-discipline-native.mjs": "8b99b5ce951cab3c1426428ad807650c61c0ffb2c346d747b73b99057b382049",
|
|
58
68
|
"local-discipline-operations.mjs": "9fcb7b8889b7718d42e1d37936485d8198d5017d405e0cdbbabdbbd12fcc9d48",
|
|
59
69
|
"local-discipline-repository.mjs": "748f691ad65366a68f2a7f8106a95b223a3027d3ff86481a111b27385e9aef57",
|
|
60
|
-
"local-discipline-snapshot.mjs": "
|
|
70
|
+
"local-discipline-snapshot.mjs": "ff1fc42a89d1eeb4977062c8698f700fc4f6ad727e1ea2ed0f255d00d63f497b",
|
|
61
71
|
"local-runner-discipline.mjs": "99935b1be0d660d6cd45f5facd911bf1e1203ec74953acef5f12a7ebafacffb2",
|
|
62
72
|
"local-integrity.d.mts": "21357f306234bd841c0d3d90bf2d09f7663f63746f897b9f38190428ae8198b3",
|
|
63
73
|
"local-equivalence-runner.mjs": "df2f406c693c4da7bb30542ec7b4d46a9336f56e9fdd263196c0f3a73d2f6e91",
|
|
@@ -66,7 +76,7 @@
|
|
|
66
76
|
"runtime/validator-runtime-v7.0.44.d.mts": "7797edbfe2f7de24da370204dce4dfd22822a1bd80df93514fff900b98afe36f",
|
|
67
77
|
"snapshot-retention.mjs": "ca46aeb36b1a5a24fe7e967031a71b9a3d33f40cb715d344402cbe0dc9c425cb",
|
|
68
78
|
"snapshot-cleanup-journal.mjs": "76a9684cc95b4eb076e1298d78a9dff37948b00d9607b8f546c599072d3ed331",
|
|
69
|
-
"IDE-EXECUTION.md": "
|
|
79
|
+
"IDE-EXECUTION.md": "26d4f32de1694c7f29ceefc5a5e5f4bba717efc5f91c37a91c399faa1574a191",
|
|
70
80
|
"REUSE-DISCIPLINE.md": "a2452911c2b50c4762b4a1374f1958059eb03efd59f63e1b50e1650c52b0dc98",
|
|
71
81
|
"install-identity.mjs": "41b8c8d8b3e265d2057a07bf7dc98066c34d6b05c65bf7159ca9609c01ee4646",
|
|
72
82
|
"package-archive.mjs": "e06db8d709db8710bead254ee950b78928088be01c58dcea383beaa5eb574e59",
|
|
@@ -84,7 +94,7 @@
|
|
|
84
94
|
"design-declaration.mjs": "f6c7f56e4697a05a0a832fcdb5a3b07ffe60aa602ba0681cfd09948bdcafc8ad",
|
|
85
95
|
"design-frameworks.mjs": "5d09a8e56068302f951a6236f36cb50e655fb6d6ffbeb2e4eb4b19f025c8a411",
|
|
86
96
|
"design-gate.mjs": "567eb666937704123ef72f26ad1145d9d32f7dfde59553381286de083e4146cb",
|
|
87
|
-
"design-lint.mjs": "
|
|
97
|
+
"design-lint.mjs": "76adb33d0faf0cfcdef7583a2f4835eccc7e49811480e2fd2b09779a81c0cbab",
|
|
88
98
|
"design-local-contracts.mjs": "f331bd1d21f30994596bd9c46008e551f3ed2b6d5eea19d4546c7da0663b768a",
|
|
89
99
|
"design-operations.mjs": "e21e9fcf9fd16115c72558c7cd7a57f7213a30934bde0f1b649aec647d1205f7",
|
|
90
100
|
"design-policy.d.mts": "48fed97fca0f97fef786f182f666d7e6e33efb814cda1991239e1c38984cf80e",
|
|
@@ -136,19 +146,19 @@
|
|
|
136
146
|
"local-autocoord17-waits.mjs": "2b0a713987822548a94e1ed3a9a891532db45383797dfc5d5bc8d1e35593cf25",
|
|
137
147
|
"local-validator-isolation17.mjs": "48e94604e28b8fddd567dfb35ff60b73fd094a5803bd49f076388b7f310f92aa",
|
|
138
148
|
"local-calctool-composition17.mjs": "ac89fcb41ab0d0d9b47c1b5696945281b0894eb064820775e36a011c76314e6a",
|
|
139
|
-
"cli.mjs": "
|
|
149
|
+
"cli.mjs": "c1fc6c58c10f00189de93ddaa8cbe4f889c62cc16c8c45d55c7b4a1498eead8e",
|
|
140
150
|
"ide-selection.mjs": "e11e2b363c06444f1dcb4cdab1eaa0eb748a379b84354e0e71fd9c2dc79a4815",
|
|
141
151
|
"ide-exit.mjs": "39d60a15b1517d402c208d22a17033976e43733be8a10dc6da386837c59b37b2",
|
|
142
152
|
"install-cleanup.mjs": "8a8e1a7dfe37427f86cd4d6e317890d0829894a9949d4216674a716b36edbc54",
|
|
143
153
|
"review-client.mjs": "3491eef68ed533174b31db3c53febb6519b8f088f71a9964644714a9a4c03c77",
|
|
144
154
|
"version.mjs": "85284d4cd5e3314b449e6ae124243f96397bcc274817b5983a79cfdd903d46fd",
|
|
145
|
-
"SKILL.md": "
|
|
146
|
-
"CAPABILITY-MAP.md": "
|
|
155
|
+
"SKILL.md": "db0ff568f83086226044726c37a0f8de517042aece8fb1676f1830c9e32f8d79",
|
|
156
|
+
"CAPABILITY-MAP.md": "517809bb20750e5de89b2dab5705c902a27fa68cf4f3f392a5d8cf2f19818888",
|
|
147
157
|
"AGREEMENT.md": "f93a68e92c457200dd024610e65f74e478b8f60860f951da818b70561f1b9bf8",
|
|
148
158
|
"DELIVERY-BOUNDARIES.md": "cb23ce71b2197085c8441ba7c5b6c05fb21f2a954bf66b4d60cfef8b15895b8b",
|
|
149
|
-
"package.json": "
|
|
159
|
+
"package.json": "71c16c55000a8d0d7cca2b935ceba15799b3e8d15be2081a7e077ce803d7b319",
|
|
150
160
|
"manifest.json": "ab06e307795bc9da5add926752b6c4dbdaf18625090261a035aa356a679c504f",
|
|
151
|
-
"release.mjs": "
|
|
161
|
+
"release.mjs": "2250561b382b61aa1f760705c872d7248266a69a96cc30e8957f42e9e48649e5",
|
|
152
162
|
"local-cli.mjs": "058ac9a4653bc12e0d031b72034ebfe6a72b91b9b23353b9fee04881c7d2e098",
|
|
153
163
|
"local-state-lock.mjs": "1dbf64264642a0851faf043e07ee9f66d2ad0508e9f799b0626246e42fae893e",
|
|
154
164
|
"local-execution.mjs": "721ed7d29bbe4ce6d088909cd84ffc440978c3c9eb0946c49a4281ee685fe3aa",
|
|
@@ -186,8 +196,13 @@
|
|
|
186
196
|
"local-stage-boundary.mjs": "84c3bb5beab29306274c5ca8a78f19a83ed664ae1b93a8372bb493158b304fe3",
|
|
187
197
|
"local-scope-candidate.mjs": "8f0bd9606e70d4a0ebacdd3cd600ec3afed85e2bb3e1760aa1144cf55d4e028a",
|
|
188
198
|
"local-scope-context.mjs": "79753abfc6c76089d17f003a1be537dfaea10d6731c542f7fc53f2a9996ed164",
|
|
189
|
-
"local-scope-files.mjs": "
|
|
190
|
-
"local-scope-repository.mjs": "
|
|
199
|
+
"local-scope-files.mjs": "4793c2a1b458346bd9099e74bbfa0623024c423e754f65ae9e01ca388b49fd36",
|
|
200
|
+
"local-scope-repository.mjs": "1e0c1aef43929237226145d3ba776facaa7e3fc89eb8f88af0a2e5ab38bcdde9",
|
|
201
|
+
"local-scope-read-set.mjs": "a5137d2e7ecffe669143fb51f0f3fba7526a881b512269858ea1e3504d9a50b2",
|
|
202
|
+
"local-scope-uni-expressions.mjs": "200f3f5284125c2674d9e797a7550e7bb7700932db237e1df2d21c3a209ac924",
|
|
203
|
+
"local-scope-uni-directives.mjs": "9951af9f98de5299bad636a09cd7f4e129c96d20939650375f7f677f7919e0c6",
|
|
204
|
+
"local-scope-uni-conditional.mjs": "8a4d03939e1daf8d257b10b44b3808b84404433113c39eff32c8643d7f9f7b18",
|
|
205
|
+
"local-scope-uni-build.mjs": "9cc45336ad6807a73c6e65d2b23f0c6606e22a423f8105710e532b50f76896c5",
|
|
191
206
|
"local-scope-create-require.mjs": "6b6a209bfcad8fe1398e99c5c8cc3af189c120b9c38e244a73dd1a99c3d91295",
|
|
192
207
|
"local-scope-require-resolution.mjs": "b24596462c8776cbefa6f0a74749d665aa928d1643c68d44798eb93e2dd5ad42",
|
|
193
208
|
"local-scope-git.mjs": "53bbbb6c4795db711b5bc164591a6ad79a561427da046d6bbe997dae6eb82829",
|
|
@@ -213,29 +228,29 @@
|
|
|
213
228
|
"local-budget-git-system-attributes.mjs": "367a4e5a88490c4d4c3717bc893a271970fe70d7705f0c1c72d6f76a442d5d21",
|
|
214
229
|
"runtime/git-native-linux-v1.mjs": "cf5cb91426a105e62c0f07a8a230dec592dba46f85a3f708b4c4e8cfcd1126c6",
|
|
215
230
|
"runtime/git-native-darwin-v1.mjs": "f88aab72dc86f94eb1115784872957cb8ed0f74205ae70e1ecd1939e7790e310",
|
|
216
|
-
"local-scope-signature.mjs": "
|
|
231
|
+
"local-scope-signature.mjs": "5aba6422031873946874307175b5a6f1fa609faa8160e1a1bb8db44c02c58d18",
|
|
217
232
|
"local-scope-config-imports.mjs": "a399407227bbdd14468633bb6d25586df7c6a30a1ef0d1a80ab7c7b499d3fadf",
|
|
218
233
|
"local-scope-config-extends.mjs": "3ab4150b846b247e9e0851221123f220c5574699af651830e751f026ab33659e",
|
|
219
234
|
"local-scope-snapshot.mjs": "c0f851470b98863a1d187825ed61ee6072d1c057b178fdc85ae29af02a3b250f",
|
|
220
235
|
"local-scope-state.mjs": "8b600a91fc0068d7a8c0bb752ddba7ed30ada93daafb118d6cba2368fd94cb27",
|
|
221
|
-
"local-scope-workspaces.mjs": "
|
|
236
|
+
"local-scope-workspaces.mjs": "7484905ab0434e1a98f95038c65003ae48e395e9cfae07a4322f481537a08392",
|
|
222
237
|
"local-task-routing.mjs": "6e2e506b2fb0e2e8d8c5147d7df32849b57a4e94a23634f01a355d45735858e4",
|
|
223
|
-
"remote-client.mjs": "
|
|
224
|
-
"cloud-task-client.mjs": "
|
|
225
|
-
"scope-runner-client.mjs": "
|
|
238
|
+
"remote-client.mjs": "d30fd61fab3171a9e41546706a57ae372786d20ea9e9c01cad39d9863c156b40",
|
|
239
|
+
"cloud-task-client.mjs": "f9085c5e6af6f179282670d2e872b85bfabac2657d3d232b1246dc23f5a6ccdd",
|
|
240
|
+
"scope-runner-client.mjs": "b85999bca05efd804325f97b6e5704623ac3fcf751c6f9760717a23f40661ad1",
|
|
226
241
|
"scope-amendment-client.mjs": "64a38deddc2dbfae543fead2cff8c9c78771b576391cc903aa58db925a138ad7",
|
|
227
|
-
"scope-amendment-state.mjs": "
|
|
242
|
+
"scope-amendment-state.mjs": "922c4fd5a71101651d40fdb11f94f09c904cc244ff2574ae6b6ee004448aad06",
|
|
228
243
|
"scope-amendment-wire.mjs": "3c4823e23bbdf330616bb675f07f9fcad7423266bd50b92e1134d226060e9b83",
|
|
229
244
|
"scope-amendment-remote.mjs": "15a0b3126248f3101a52e3d7742f9a816dd3d8e58f21bac33e99e810e86cc4fd",
|
|
230
|
-
"scope-amendment-observer.mjs": "
|
|
245
|
+
"scope-amendment-observer.mjs": "de796f2aca2f3bc7f33ae3323b07d98096c0f16b1ffde70e3055610d70d18020",
|
|
231
246
|
"scope-amendment-mutation.mjs": "fa24191df290efad29d41eca3d1a081981fefde02b7dc4a11c75c6118a69106e",
|
|
232
247
|
"scope-amendment-reference.mjs": "0537e53a1bea4b695f4804c5051261778c88f05b1ae4aff86c709dcfe83aa148",
|
|
233
248
|
"native-client.mjs": "6f5575909bae9daba643287f876ffa0f9ff1c53a367b32a40145d740456d6605",
|
|
234
249
|
"native-notification.mjs": "8859a26c6f13d222711f763acf49ed8546b3306cf71f990643ac31a5ccaf1ba1",
|
|
235
250
|
"local-peer-status.mjs": "a971bcc69d60bb32b875ca5bb4297d948631d5d2821b812c279613ea059a8b4f",
|
|
236
|
-
"cloud-watch-client.mjs": "
|
|
251
|
+
"cloud-watch-client.mjs": "2042392cd62f1596a35ef3f6cb376f8ed67790351576b007e32f134ce018aec1",
|
|
237
252
|
"cloud-event-stream.mjs": "e0eec9fc3e0613094523929634f25030df5ca5c5b5fe2c1e1a4586ab10574808",
|
|
238
|
-
"ide-presentation.mjs": "
|
|
253
|
+
"ide-presentation.mjs": "d826afe0dfcc38906ba76dcbbe021807731587c38026148624546c334057e7f3",
|
|
239
254
|
"automatic-feedback-client.mjs": "532312d29e66fa211ea3fe879d9add1dd48841ee5ce82800b4b06252a160a255",
|
|
240
255
|
"task-entry-client.mjs": "940fb068afe28a2a34fe96e285e149afdd9ba79649c0c65cde37ec4ed71ae39d",
|
|
241
256
|
"task-identity.mjs": "e0e6cf1f48bfa5ee3c5cb86a3c21adfce6d66b4220f4a164ca099263c7a09fb4",
|
|
@@ -260,11 +275,11 @@
|
|
|
260
275
|
"workflow-local-request.mjs": "4e24c543ce386292a87dc9cd41f90d23375f12079cacffc515c8cd01fd571780",
|
|
261
276
|
"task-message-entry.mjs": "31d10056cb905237cd5649e8eb067009ff1612ec5dc1061e0373209fbc0b646a",
|
|
262
277
|
"task-message-cli.mjs": "3ca65e96c28129b3bd5cac962d106e0859a1f17df1f6a66ee543c6efc22f918d",
|
|
263
|
-
"local-contracts.mjs": "
|
|
278
|
+
"local-contracts.mjs": "0548faf3ecc4f3124c823ccd926f811580f4ba50a15bd334ff6d550e6eca013d",
|
|
264
279
|
"local-contract-types.mjs": "85e71fa4dd67e351a4b67573c740bcdb1661cede53f097189f11837771e75e91",
|
|
265
280
|
"local-archguard-ast.mjs": "7ff7df9dab0d98ed62983add751c80edea598bc94ef4f38ede0ebd4d41226c87",
|
|
266
281
|
"local-archguard-checkpoint.mjs": "37896902520cc995720c96288e4a5ed3585952b55c9c35be281f91fa754c71ec",
|
|
267
|
-
"local-archguard-components.mjs": "
|
|
282
|
+
"local-archguard-components.mjs": "07d0554355eebba7989b373d019682d194a0d37a031abbcc6b4b24b19f0a75e8",
|
|
268
283
|
"local-archguard-contract.mjs": "cfc397a1ce171ab84f8bf1db152e6d8d280b7ca041da56a7a4cd62b02c2e2e89",
|
|
269
284
|
"local-archguard-contracts.mjs": "29e9b86f14dc086aa0b791c874d6efc50d849f806b3f2b8725481114f01ba8ba",
|
|
270
285
|
"local-archguard-evaluate.mjs": "c34f0956e7a4f1afaa1554c03e238a350dc8a981dc595cf4ed065fb14f733f93",
|
|
@@ -288,7 +303,7 @@
|
|
|
288
303
|
"local-calctool-runtime.mjs": "9070b6900d1782bf77357fea1cc522bf796898d56929f96d7cb935b3036ac82f",
|
|
289
304
|
"local-calctool-storage.mjs": "4c3f352847aeb368dea1247759a1055beeab25534adf25b6e7323196d76fd684",
|
|
290
305
|
"local-mutation-files.mjs": "087b00e8424a135e783eb432271012a71e55eeb4a5e30119490d1bc0b2160320",
|
|
291
|
-
"local-mutation-snapshot.mjs": "
|
|
306
|
+
"local-mutation-snapshot.mjs": "69c0ff0b67b2e6913b1d9f8247bf48c31d62f4f5ae1668c573a0ade06c01d105",
|
|
292
307
|
"local-mutation-audit.mjs": "5a30ee3446f632e032ffcfe46bcd97d6dfc0f099a76ea5185c3f9a9118c4f6cb",
|
|
293
308
|
"local-mutation-wire.mjs": "6d00400e531c693c3e8bfd0c2a24fcc486127f84aafc56ee450dcec7f534eb05",
|
|
294
309
|
"local-mutation-binding.mjs": "4440d792453a07a375b635fa5a91db607e58162824baced5c79a9a513f4ec918",
|
package/release.mjs
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { FINAL_GATE16_PACKAGE_FILES, withFinalGate16ReleaseLabels } from './local-final-gate16-release.mjs'
|
|
2
2
|
import { REUSE_DISCIPLINE_SOURCE_FILES, reuseDisciplineReleaseLabels } from './reuse-discipline-release.mjs'
|
|
3
3
|
import { DESIGN_GATE_SOURCE_FILES, designGateReleaseLabels } from './design-release.mjs'
|
|
4
|
+
import { SCOPE_CONTEXT_SOURCE_FILES, scopeContextReleaseNote } from './scope-context-release.mjs'
|
|
4
5
|
import { createHash } from 'node:crypto'
|
|
5
6
|
import { readFile, writeFile, rename, rm } from 'node:fs/promises'
|
|
6
7
|
import path from 'node:path'
|
|
@@ -48,7 +49,7 @@ const memberContinuationSourceFiles = Object.freeze([
|
|
|
48
49
|
'workflow-observation-wire.mjs',
|
|
49
50
|
])
|
|
50
51
|
const sourceFiles = [
|
|
51
|
-
'cloud-task-images.mjs', 'model-images.mjs', 'model-images.d.mts', 'cli-input.mjs',
|
|
52
|
+
...SCOPE_CONTEXT_SOURCE_FILES, 'cloud-locale.mjs', 'cloud-locale.d.mts', 'cloud-task-images.mjs', 'model-images.mjs', 'model-images.d.mts', 'cli-input.mjs',
|
|
52
53
|
'scope-amendment-retirement.mjs', 'scope-amendment-consumption.mjs', 'mutation-connection-state.mjs', 'mutation-challenge-refresh.mjs',
|
|
53
54
|
'local-scope-font.mjs', 'local-scope-zip.mjs', 'member-producer-repair-authority.mjs',
|
|
54
55
|
'local-mutation-completion-evidence.mjs', 'local-mutation-environment-observation.mjs', 'local-mutation-finder-observation.mjs', 'local-finder-store.mjs', 'local-finder-plist.mjs',
|
|
@@ -90,7 +91,7 @@ const sourceFiles = [
|
|
|
90
91
|
'local-scope-candidate.mjs',
|
|
91
92
|
'local-scope-context.mjs',
|
|
92
93
|
'local-scope-files.mjs',
|
|
93
|
-
'local-scope-repository.mjs',
|
|
94
|
+
'local-scope-repository.mjs', 'local-scope-read-set.mjs', 'local-scope-uni-expressions.mjs', 'local-scope-uni-directives.mjs', 'local-scope-uni-conditional.mjs', 'local-scope-uni-build.mjs',
|
|
94
95
|
'local-scope-create-require.mjs',
|
|
95
96
|
'local-scope-require-resolution.mjs',
|
|
96
97
|
'local-scope-git.mjs',
|
|
@@ -309,6 +310,7 @@ function releaseNote(changed) {
|
|
|
309
310
|
if (suppliedZh && suppliedEn) return {
|
|
310
311
|
zh: suppliedZh.replaceAll(/\s+/g, ' '), en: suppliedEn.replaceAll(/\s+/g, ' '),
|
|
311
312
|
}
|
|
313
|
+
if (changed.some(file => SCOPE_CONTEXT_SOURCE_FILES.includes(file))) return scopeContextReleaseNote
|
|
312
314
|
if (changed.some(file => file.startsWith('scope-amendment-'))) return {
|
|
313
315
|
zh: '新增同一任务的精确范围补正:原账号审核文件哈希与写入/只读角色,原S签名真实事实并重评原合同;计划、写入和结算绑定不可变范围修订,改后刷新保留原M消费证据与失败历史。',
|
|
314
316
|
en: 'Add same-task exact scope amendment with original owner review of file hashes and write/read-only roles, original S observations and native contract reassessment; bind plans, writes and settlement to immutable scope revisions and retain actual M consumption and failure history during post-write refresh.',
|
|
@@ -450,7 +452,6 @@ async function writeAll(changes) {
|
|
|
450
452
|
throw error
|
|
451
453
|
}
|
|
452
454
|
}
|
|
453
|
-
|
|
454
455
|
const metadata = JSON.parse(await read('package.json'))
|
|
455
456
|
const manifest = JSON.parse(await read('manifest.json'))
|
|
456
457
|
const state = JSON.parse(await read(stateFile))
|
package/releases.json
CHANGED
|
@@ -1,4 +1,16 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.1.70",
|
|
4
|
+
"date": "2026-10-20",
|
|
5
|
+
"zh": "云端沙箱固定中英文输出语言,界面、通知和 Blueprint 文档正文按对应语种显示,原始证据单列来源并保留旧流程精确版本。修复 uni-app 默认条件编译分支解析与长扫描后的原任务签名挑战衔接,核对真实读集并保留原审批、完整路径、快照及失败历史。",
|
|
6
|
+
"en": "Freeze cloud sandbox output language across presentation, notifications and Blueprint document prose; preserve original source evidence and exact historical runtimes. Fix default uni-app conditional branch inspection and renew the original signing challenge after long scans, rechecking actual reads while retaining approvals, complete paths, snapshots and failure history."
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"version": "0.1.69",
|
|
10
|
+
"date": "2026-10-20",
|
|
11
|
+
"zh": "新增首次范围门禁前的构建上下文纠正:原账号审核真实配置和构建证据,原 S 签名完整路径快照,通过服务挑战追加上下文权威记录;保留原 flow、绑定、旧上下文和失败历史,不授予写入或完成权限。",
|
|
12
|
+
"en": "Add build-context recovery before the first scope gate: original owner review of actual configuration and build evidence, original S proof of all target paths, and challenge-bound append-only context authority. Preserve the original flow, binding, contexts and failures without granting writes or completion."
|
|
13
|
+
},
|
|
2
14
|
{
|
|
3
15
|
"version": "0.1.68",
|
|
4
16
|
"date": "2026-10-20",
|
package/remote-client.mjs
CHANGED
|
@@ -40,6 +40,7 @@ export function buildInvocation(operation, input) {
|
|
|
40
40
|
'handoff-prepare', 'handoff-release', 'handoff-claim', 'handoff-status', 'handoff-resume', 'handoff-execution-authority', 'mutation-snapshot-challenge', 'mutation-pass-issue', 'mutation-pass-settle',
|
|
41
41
|
'member-observation-admit', 'member-observation-report', 'member-observation-status',
|
|
42
42
|
'scope-runner-prepare', 'scope-runner-register', 'scope-runner-challenge', 'scope-runner-attest',
|
|
43
|
+
'scope-runner-context-review', 'scope-runner-context-status', 'scope-runner-context-challenge', 'scope-runner-context-apply',
|
|
43
44
|
'start', 'continue'].includes(operation)) throw new Error('Invalid entrorove operation');
|
|
44
45
|
if (!input || typeof input !== 'object' || Array.isArray(input)) throw new Error('Input must be a JSON object');
|
|
45
46
|
const id = requestId(operation, input);
|
|
@@ -27,7 +27,9 @@ export async function observeScopeAmendment(location, state) {
|
|
|
27
27
|
if (!state.snapshotId) { state.snapshotId = `scope-amend-${randomUUID()}`; await saveScopeAmendmentState(location, state); }
|
|
28
28
|
const input = { repositoryRoot: location.root, home: location.home, flowId: challenge.flowId, stepId: challenge.stepId,
|
|
29
29
|
snapshotId: state.snapshotId, paths: challenge.files.map(file => file.path).sort(),
|
|
30
|
-
contractDigest: challenge.proposalDigest, importContexts: location.binding.importContexts,
|
|
30
|
+
contractDigest: challenge.proposalDigest, importContexts: location.contextAuthority?.record.importContexts ?? location.binding.importContexts,
|
|
31
|
+
...(location.contextAuthority ? { contextRevisionDigest: location.contextAuthority.revisionDigest,
|
|
32
|
+
contextEvidence: location.contextAuthority.record.evidence } : {}),
|
|
31
33
|
scopeCreatePaths: challenge.files.filter(file => file.access === 'create').map(file => file.path) };
|
|
32
34
|
if (!state.snapshot) {
|
|
33
35
|
if (!state.snapshotStarted) {
|
|
@@ -7,6 +7,7 @@ import { retainedScope } from './local-scope-state.mjs';
|
|
|
7
7
|
import { mutationHome14, mutationFile14, privateMutationDirectory14,
|
|
8
8
|
readMutationJson14, atomicMutationJson14 } from './local-mutation-files.mjs';
|
|
9
9
|
import { trustedOrigin } from './remote-transport.mjs';
|
|
10
|
+
import { boundScopeContexts } from './scope-context-state.mjs';
|
|
10
11
|
|
|
11
12
|
const fail = message => scopeFail('ENTROROVE_SCOPE_AMENDMENT_STATE', message);
|
|
12
13
|
const maximumStateBytes = 1_000_000;
|
|
@@ -78,8 +79,9 @@ export async function scopeAmendmentLocation(repositoryRoot, input, dependencies
|
|
|
78
79
|
originalFactsDigest: original.originalFactsDigest, originalSnapshotDigest: original.originalSnapshot.digest };
|
|
79
80
|
const directory = path.join(base, 'amendments', sha256(canonical(input)));
|
|
80
81
|
await privateMutationDirectory14(directory, { privateFrom: stateRoot });
|
|
82
|
+
const contextAuthority = await boundScopeContexts(base, binding, dependencies);
|
|
81
83
|
return { root, home, stateRoot, directory, file: path.join(directory, 'journal.json'), identity,
|
|
82
|
-
binding, key, signerConfigPath, original };
|
|
84
|
+
binding, key, signerConfigPath, original, contextAuthority };
|
|
83
85
|
}
|
|
84
86
|
export async function readScopeAmendmentState(location) {
|
|
85
87
|
let value;
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { sign } from 'node:crypto';
|
|
3
|
+
import { canonical } from './local-integrity.mjs';
|
|
4
|
+
import { withStateLock } from './local-state-lock.mjs';
|
|
5
|
+
import { bootstrapCloudMutationAuthority } from './cloud-mutation-authority.mjs';
|
|
6
|
+
import { contextInput, contextFail, retainedContexts, originalContextDigest, contextChallenge } from './scope-context-wire.mjs';
|
|
7
|
+
import { scopeContextLocation, effectiveScopeContexts, retainContextAuthority,
|
|
8
|
+
saveContextJournal } from './scope-context-state.mjs';
|
|
9
|
+
import { contextRemote } from './scope-context-remote.mjs';
|
|
10
|
+
import { inspectContextEvidence, observeScopeContext, prepareScopeContext } from './scope-context-observer.mjs';
|
|
11
|
+
import { contextJournal, renewContextChallenge } from './scope-context-journal.mjs';
|
|
12
|
+
|
|
13
|
+
const schemaVersion = 'entrorove.scope-context-connection/1.0';
|
|
14
|
+
function proposalFor(status, input, location) {
|
|
15
|
+
const proposal = status.proposal;
|
|
16
|
+
if (!proposal || proposal.proposalId !== input.proposalId || proposal.proposalDigest !== input.proposalDigest
|
|
17
|
+
|| ['flowId', 'runnerId', 'repositoryId', 'keyId'].some(field => proposal[field] !== location.binding[field])
|
|
18
|
+
|| proposal.localBindingDigest !== location.localBindingDigest
|
|
19
|
+
|| canonical(proposal.targetPaths) !== canonical(location.binding.targetPaths)
|
|
20
|
+
|| !['pending', 'approved', 'declined'].includes(proposal.approval?.status)) contextFail('Current account has no matching original context proposal');
|
|
21
|
+
retainedContexts(location.binding.importContexts, proposal.importContexts); return proposal;
|
|
22
|
+
}
|
|
23
|
+
function waiting(value, flowId) {
|
|
24
|
+
const status = value.proposal?.approval?.status;
|
|
25
|
+
return { ...value, schemaVersion, status: status === 'declined' ? 'blocked' : 'needs-input', flowId,
|
|
26
|
+
grantsExecutionAuthority: false, claimsCompletion: false,
|
|
27
|
+
nextStep: value.nextStep ?? { operation: 'interaction-answer', requiresOriginalOwnerApproval: true,
|
|
28
|
+
interactionId: value.proposal?.approval?.interactionId, interactionDigest: value.proposal?.approval?.interactionDigest } };
|
|
29
|
+
}
|
|
30
|
+
async function liveStatus(location, state, dependencies) {
|
|
31
|
+
if (!state.checked) await contextRemote('checked', 'scope-runner-context-status', {
|
|
32
|
+
flowId: location.binding.flowId, attemptId: state.attemptId }, state, location, dependencies);
|
|
33
|
+
const effective = await effectiveScopeContexts(location);
|
|
34
|
+
if (!Number.isSafeInteger(state.checked.expectedRevision) || state.checked.expectedRevision !== (effective?.record.revision ?? 0)) contextFail('Live context revision differs from its retained original history');
|
|
35
|
+
if ((state.checked.effective?.revisionDigest ?? null) !== (effective?.revisionDigest ?? null)) contextFail('Live context head differs from retained signed history; recover its original apply request');
|
|
36
|
+
return state.checked;
|
|
37
|
+
}
|
|
38
|
+
async function review(location, state, dependencies) {
|
|
39
|
+
if (state.reviewed) return waiting(state.reviewed, location.binding.flowId);
|
|
40
|
+
const status = await liveStatus(location, state, dependencies), head = await effectiveScopeContexts(location), input = state.input;
|
|
41
|
+
retainedContexts(head?.record.importContexts ?? location.binding.importContexts, input.importContexts);
|
|
42
|
+
if (!state.proposal) {
|
|
43
|
+
const evidence = await inspectContextEvidence(location, input.importContexts, input.evidencePaths);
|
|
44
|
+
state.proposal = { schemaVersion: 'entrorove.scope-context-proposal/1.0', flowId: location.binding.flowId,
|
|
45
|
+
runnerId: location.binding.runnerId, repositoryId: location.binding.repositoryId, keyId: location.binding.keyId,
|
|
46
|
+
localBindingDigest: location.localBindingDigest, expectedRevision: status.expectedRevision,
|
|
47
|
+
previousDigest: head?.revisionDigest ?? originalContextDigest(location), originalImportContexts: location.binding.importContexts,
|
|
48
|
+
importContexts: input.importContexts, evidence, reason: input.reason, attemptId: state.attemptId };
|
|
49
|
+
state.signature = sign(null, Buffer.from(canonical(state.proposal)), location.key).toString('base64url');
|
|
50
|
+
await saveContextJournal(location, state);
|
|
51
|
+
}
|
|
52
|
+
const output = await contextRemote('reviewed', 'scope-runner-context-review', { flowId: location.binding.flowId,
|
|
53
|
+
proposal: state.proposal, signature: state.signature }, state, location, dependencies);
|
|
54
|
+
state.completed = true; await saveContextJournal(location, state); return waiting(output, location.binding.flowId);
|
|
55
|
+
}
|
|
56
|
+
async function applied(location, state) {
|
|
57
|
+
const effective = state.applied.contextAuthority;
|
|
58
|
+
const challenge = contextChallenge((state.signingChallenge ?? state.challenged).challenge, location, state.proposal, { allowExpired: true });
|
|
59
|
+
if (state.applied.grantsExecutionAuthority !== false || !effective?.record
|
|
60
|
+
|| canonical(effective.record.attestation) !== canonical(state.attestation)
|
|
61
|
+
|| ['proposalId', 'proposalDigest', 'ownerId', 'taskDigest', 'chainDigest'].some(field => effective.record[field] !== challenge[field])
|
|
62
|
+
|| canonical(effective.record.importContexts) !== canonical(challenge.importContexts)
|
|
63
|
+
|| canonical(effective.record.evidence) !== canonical(challenge.evidence)) contextFail('Applied context authority differs from this exact actual candidate');
|
|
64
|
+
const retained = await retainContextAuthority(location, effective);
|
|
65
|
+
state.completed = true; await saveContextJournal(location, state);
|
|
66
|
+
return { schemaVersion, status: 'succeeded', flowId: location.binding.flowId, contextRevisionDigest: retained.revisionDigest,
|
|
67
|
+
revision: retained.record.revision, grantsExecutionAuthority: false, claimsCompletion: false, nextOperation: 'scope-connect',
|
|
68
|
+
nextInput: { flowId: location.binding.flowId, paths: [...location.binding.targetPaths], importContexts: retained.record.importContexts } };
|
|
69
|
+
}
|
|
70
|
+
async function apply(location, state, dependencies) {
|
|
71
|
+
if (state.applied) return applied(location, state);
|
|
72
|
+
const status = await liveStatus(location, state, dependencies), proposal = proposalFor(status, state.input, location);
|
|
73
|
+
if (proposal.approval.status !== 'approved') {
|
|
74
|
+
state.completed = true; await saveContextJournal(location, state); return waiting(status, location.binding.flowId);
|
|
75
|
+
}
|
|
76
|
+
state.proposal = proposal; await saveContextJournal(location, state);
|
|
77
|
+
if (!state.challenged) await contextRemote('challenged', 'scope-runner-context-challenge', { flowId: location.binding.flowId,
|
|
78
|
+
proposalId: proposal.proposalId, proposalDigest: proposal.proposalDigest, attemptId: state.attemptId }, state, location, dependencies);
|
|
79
|
+
if (!state.attestation) {
|
|
80
|
+
const prepared = await prepareScopeContext(location, state, proposal);
|
|
81
|
+
state.attestation = await observeScopeContext(location, state, proposal, prepared,
|
|
82
|
+
() => renewContextChallenge(location, state, proposal, dependencies));
|
|
83
|
+
await saveContextJournal(location, state);
|
|
84
|
+
}
|
|
85
|
+
await contextRemote('applied', 'scope-runner-context-apply', { flowId: location.binding.flowId,
|
|
86
|
+
proposalId: proposal.proposalId, proposalDigest: proposal.proposalDigest, attestation: state.attestation }, state, location, dependencies);
|
|
87
|
+
return applied(location, state);
|
|
88
|
+
}
|
|
89
|
+
async function run(location, input, dependencies) {
|
|
90
|
+
const state = await contextJournal(location, input);
|
|
91
|
+
if (state.pending) await contextRemote(state.pending.stage, state.pending.operation, state.pending.input, state, location, dependencies);
|
|
92
|
+
try {
|
|
93
|
+
if (input.action === 'review') return await review(location, state, dependencies);
|
|
94
|
+
if (input.action === 'apply') return await apply(location, state, dependencies);
|
|
95
|
+
const status = await liveStatus(location, state, dependencies);
|
|
96
|
+
state.completed = true; await saveContextJournal(location, state);
|
|
97
|
+
return { schemaVersion, ...status, status: 'succeeded', flowId: input.flowId, grantsExecutionAuthority: false, claimsCompletion: false };
|
|
98
|
+
} catch (error) {
|
|
99
|
+
if (!state.pending) { state.rejection ??= { code: error.code, message: error.message }; await saveContextJournal(location, state); }
|
|
100
|
+
throw error;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
export async function runScopeContext(repositoryRoot, input, dependencies) {
|
|
104
|
+
try {
|
|
105
|
+
contextInput(input); await dependencies.install();
|
|
106
|
+
if (!await dependencies.agreementAccepted(dependencies.home)) return dependencies.agreementRequired(dependencies.home);
|
|
107
|
+
await bootstrapCloudMutationAuthority(dependencies);
|
|
108
|
+
const location = await scopeContextLocation(repositoryRoot, input.flowId, dependencies);
|
|
109
|
+
return await withStateLock(path.join(location.base, 'connection'), () => run(location, input, dependencies));
|
|
110
|
+
} catch (error) {
|
|
111
|
+
return { schemaVersion, status: 'blocked', flowId: input?.flowId,
|
|
112
|
+
code: error?.code?.startsWith('ENTROROVE_') ? error.code : 'ENTROROVE_SCOPE_CONTEXT_PREREQUISITE',
|
|
113
|
+
message: error?.code?.startsWith('ENTROROVE_') ? error.message : 'Context recovery stopped; preserve original signer, binding, journal and evidence.',
|
|
114
|
+
...(error?.requestId ? { requestId: error.requestId } : {}), ...(error?.output ? { output: error.output } : {}),
|
|
115
|
+
...(error?.outcomeUnknown ? { outcomeUnknown: true, nextAction: { operation: 'scope-context', method: 'GET',
|
|
116
|
+
requestId: error.requestId, reuseOriginalInput: true, repeatPost: false } } : {}) };
|
|
117
|
+
}
|
|
118
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { canonical, sha256 } from './local-integrity.mjs';
|
|
4
|
+
import { atomicMutationJson14, readMutationJson14 } from './local-mutation-files.mjs';
|
|
5
|
+
import { contextFail } from './scope-context-wire.mjs';
|
|
6
|
+
import { readContextJournal, saveContextJournal } from './scope-context-state.mjs';
|
|
7
|
+
import { contextRemote } from './scope-context-remote.mjs';
|
|
8
|
+
|
|
9
|
+
export async function archiveContextAttempt(location, state) {
|
|
10
|
+
if (!state.attemptId) return;
|
|
11
|
+
const file = path.join(location.directory, `${state.attemptId}-${sha256(canonical(state))}.json`);
|
|
12
|
+
try { if (canonical(await readMutationJson14(file)) !== canonical(state)) contextFail('Context attempt history changed'); }
|
|
13
|
+
catch (error) { if (error.code !== 'ENOENT') throw error; await atomicMutationJson14(file, state, { privateFrom: location.stateRoot }); }
|
|
14
|
+
}
|
|
15
|
+
function reusableSnapshot(state, input) {
|
|
16
|
+
return input.action === 'apply' && state.snapshot && state.challenged && !state.pending && !state.completed && !state.applied
|
|
17
|
+
&& state.rejection && !state.rejection.requestId && !state.rejection.output;
|
|
18
|
+
}
|
|
19
|
+
export async function contextJournal(location, input) {
|
|
20
|
+
let state = await readContextJournal(location, input);
|
|
21
|
+
if (!state.previous && reusableSnapshot(state, input)) {
|
|
22
|
+
await archiveContextAttempt(location, state);
|
|
23
|
+
for (const field of ['rejection', 'checked', 'attestation', 'signingChallenge', 'signingAttemptId']) delete state[field];
|
|
24
|
+
await saveContextJournal(location, state);
|
|
25
|
+
} else if (state.previous || !state.pending && !state.applied && (state.rejection
|
|
26
|
+
|| input.action === 'status' && state.completed || input.action === 'apply' && state.completed)) {
|
|
27
|
+
await archiveContextAttempt(location, state.previous ?? state); state = {};
|
|
28
|
+
}
|
|
29
|
+
if (!state.attemptId) {
|
|
30
|
+
state = { schemaVersion: 'entrorove.scope-context-journal/1.0', localBindingDigest: location.localBindingDigest,
|
|
31
|
+
input, attemptId: randomUUID() }; await saveContextJournal(location, state);
|
|
32
|
+
}
|
|
33
|
+
return state;
|
|
34
|
+
}
|
|
35
|
+
export async function renewContextChallenge(location, state, proposal, dependencies) {
|
|
36
|
+
if (state.pending) contextFail('Recover the original pending request before any challenge renewal');
|
|
37
|
+
await archiveContextAttempt(location, state);
|
|
38
|
+
delete state.signingChallenge;
|
|
39
|
+
state.signingAttemptId = randomUUID(); await saveContextJournal(location, state);
|
|
40
|
+
const output = await contextRemote('signingChallenge', 'scope-runner-context-challenge', { flowId: location.binding.flowId,
|
|
41
|
+
proposalId: proposal.proposalId, proposalDigest: proposal.proposalDigest, attemptId: state.signingAttemptId },
|
|
42
|
+
state, location, dependencies);
|
|
43
|
+
return output.challenge;
|
|
44
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { canonical, sha256 } from './local-integrity.mjs';
|
|
3
|
+
import { mutationHome14, readMutationJson14 } from './local-mutation-files.mjs';
|
|
4
|
+
import { contextPrivate, effectiveScopeContexts } from './scope-context-state.mjs';
|
|
5
|
+
import { contextExact, contextFail, contextList } from './scope-context-wire.mjs';
|
|
6
|
+
import { hydrateCloudMutationAuthority } from './cloud-mutation-authority.mjs';
|
|
7
|
+
import { trustedOrigin } from './remote-transport.mjs';
|
|
8
|
+
|
|
9
|
+
export async function scopeContextObservation(input, root, apiOrigin = 'https://entrorove.com') {
|
|
10
|
+
if (!input.flowId) return null;
|
|
11
|
+
const home = await mutationHome14(input.home), origin = trustedOrigin(apiOrigin);
|
|
12
|
+
const stateRoot = path.join(home, '.entrorove'), base = path.join(stateRoot, 'scope-runners', sha256(`${origin}:${input.flowId}:${root}`));
|
|
13
|
+
try { await contextPrivate(path.join(base, 'context-authority'), 'directory'); }
|
|
14
|
+
catch (error) { if (error.code === 'ENOENT') return null; throw error; }
|
|
15
|
+
await contextPrivate(path.join(base, 'identity/binding.json'), 'file', 1_000_000);
|
|
16
|
+
const binding = await readMutationJson14(path.join(base, 'identity/binding.json'));
|
|
17
|
+
contextExact(binding, ['schemaVersion', 'flowId', 'repositoryRoot', 'apiOrigin', 'targetPaths', 'importContexts', 'runnerId', 'repositoryId', 'publicKey', 'keyId']);
|
|
18
|
+
if (binding.schemaVersion !== 'entrorove.local-scope-binding/1.0' || binding.flowId !== input.flowId
|
|
19
|
+
|| binding.repositoryRoot !== root || binding.apiOrigin !== origin) contextFail('Snapshot contexts require their original local flow, root and repository binding');
|
|
20
|
+
contextList(binding.importContexts);
|
|
21
|
+
if (!await hydrateCloudMutationAuthority(home, origin)) contextFail('Snapshot context authority requires its existing private local public-key pin');
|
|
22
|
+
const head = await effectiveScopeContexts({ base, binding, localBindingDigest: sha256(canonical(binding)) });
|
|
23
|
+
if (!head) contextFail('Snapshot context history has no accepted signed head');
|
|
24
|
+
return { apiOrigin: origin, ...head };
|
|
25
|
+
}
|
|
26
|
+
function boundInput(input, context) {
|
|
27
|
+
if (!context) return input;
|
|
28
|
+
const fields = { importContexts: context.record.importContexts, contextRevisionDigest: context.revisionDigest,
|
|
29
|
+
contextEvidence: context.record.evidence };
|
|
30
|
+
if (Object.keys(fields).some(field => Object.hasOwn(input, field) && canonical(input[field]) !== canonical(fields[field]))) {
|
|
31
|
+
contextFail('Mutation observation cannot replace its original approved snapshot contexts');
|
|
32
|
+
}
|
|
33
|
+
return { ...input, ...fields };
|
|
34
|
+
}
|
|
35
|
+
export async function scopeContextSnapshotInput(input, root, context, { initial = false } = {}) {
|
|
36
|
+
if (context) contextExact(context, ['apiOrigin', 'record', 'revisionDigest']);
|
|
37
|
+
const current = await scopeContextObservation(input, root, context?.apiOrigin);
|
|
38
|
+
if (!context && current && !initial || context && (!current || canonical(context) !== canonical(current))) {
|
|
39
|
+
contextFail('Mutation snapshot context authority differs from its original signed same-flow history');
|
|
40
|
+
}
|
|
41
|
+
return { input: boundInput(input, context ?? (initial ? current : null)), context: context ?? (initial ? current : null) };
|
|
42
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { randomUUID, sign } from 'node:crypto';
|
|
2
|
+
import { canonical } from './local-integrity.mjs';
|
|
3
|
+
import { scopeRead, scopeTarget } from './local-scope-files.mjs';
|
|
4
|
+
import { snapshotPlan, snapshotVerify } from './local-execution.mjs';
|
|
5
|
+
import { collectScopeFacts } from './local-scope-repository.mjs';
|
|
6
|
+
import { readScopeSnapshot, verifyFreshScopeSnapshot } from './local-scope-snapshot.mjs';
|
|
7
|
+
import { attestScopeFacts } from './local-scope-signature.mjs';
|
|
8
|
+
import { contextChallenge, contextFail } from './scope-context-wire.mjs';
|
|
9
|
+
import { saveContextJournal } from './scope-context-state.mjs';
|
|
10
|
+
|
|
11
|
+
export async function inspectContextEvidence(location, contexts, evidencePaths) {
|
|
12
|
+
const paths = new Set(evidencePaths);
|
|
13
|
+
for (const context of contexts) {
|
|
14
|
+
const directory = await scopeTarget(location.root, context.sourcePrefix);
|
|
15
|
+
if (!directory.stat.isDirectory()) contextFail('Context source prefix must be an actual repository directory');
|
|
16
|
+
paths.add(context.configPath);
|
|
17
|
+
}
|
|
18
|
+
if (paths.size > 200) contextFail('Context evidence exceeds its 200-file inspection bound');
|
|
19
|
+
const evidence = [];
|
|
20
|
+
for (const relative of [...paths].sort()) {
|
|
21
|
+
const target = await scopeTarget(location.root, relative);
|
|
22
|
+
if (!target.stat.isFile() || target.stat.size > 1_048_576) contextFail('Build evidence must be an actual ordinary bounded repository file');
|
|
23
|
+
const read = await scopeRead(location.root, relative, { repositoryRoot: location.root });
|
|
24
|
+
evidence.push({ path: relative, sha256: read.sha256 });
|
|
25
|
+
}
|
|
26
|
+
return evidence;
|
|
27
|
+
}
|
|
28
|
+
function observationInput(location, state, proposal, challenge) {
|
|
29
|
+
return { repositoryRoot: location.root, home: location.home, flowId: challenge.flowId, stepId: challenge.stepId,
|
|
30
|
+
snapshotId: state.snapshotId, paths: [...location.binding.targetPaths], importContexts: challenge.importContexts,
|
|
31
|
+
contextRevisionDigest: proposal.proposalDigest, contextEvidence: challenge.evidence,
|
|
32
|
+
signerConfigPath: location.signerConfigPath, ownerId: challenge.ownerId,
|
|
33
|
+
task: challenge.task, taskDigest: challenge.taskDigest, chainDigest: challenge.chainDigest,
|
|
34
|
+
repositoryId: challenge.repositoryId, challenge: challenge.challenge };
|
|
35
|
+
}
|
|
36
|
+
export async function prepareScopeContext(location, state, proposal) {
|
|
37
|
+
// An expired server challenge can still identify read-only preparation; it cannot sign or apply.
|
|
38
|
+
const challenge = contextChallenge(state.challenged.challenge, location, proposal, { allowExpired: true });
|
|
39
|
+
const evidence = await inspectContextEvidence(location, challenge.importContexts, challenge.evidence.map(file => file.path));
|
|
40
|
+
if (canonical(evidence) !== canonical(challenge.evidence)) contextFail('Actual build configuration or loader evidence changed since review');
|
|
41
|
+
if (!state.snapshotId) { state.snapshotId = `context-${randomUUID()}`; await saveContextJournal(location, state); }
|
|
42
|
+
const input = observationInput(location, state, proposal, challenge);
|
|
43
|
+
if (!state.snapshot) {
|
|
44
|
+
if (state.snapshotStarted) contextFail('Interrupted context snapshot must be inspected before another observation; preserve its files');
|
|
45
|
+
state.snapshotStarted = true; await saveContextJournal(location, state);
|
|
46
|
+
try { state.snapshot = await snapshotPlan(input); }
|
|
47
|
+
catch (error) { delete state.snapshotStarted; await saveContextJournal(location, state); throw error; }
|
|
48
|
+
await saveContextJournal(location, state);
|
|
49
|
+
}
|
|
50
|
+
const verified = await snapshotVerify(input);
|
|
51
|
+
if (verified.verified !== true || verified.receipt.snapshotDigest !== state.snapshot.snapshotDigest) contextFail('Actual context candidate snapshot did not verify');
|
|
52
|
+
const snapshot = await readScopeSnapshot(input, location.root);
|
|
53
|
+
const facts = await collectScopeFacts(location.root, input.paths, undefined, snapshot.known, input);
|
|
54
|
+
facts.snapshotEvidence = await verifyFreshScopeSnapshot(input, location.root, facts);
|
|
55
|
+
return { input, facts, evidence };
|
|
56
|
+
}
|
|
57
|
+
function sameObservation(candidate, input, challenge) {
|
|
58
|
+
const withoutNonce = value => Object.fromEntries(Object.entries(value).filter(([field]) => field !== 'challenge'));
|
|
59
|
+
if (canonical(withoutNonce(candidate.input)) !== canonical(withoutNonce(input))
|
|
60
|
+
|| canonical(candidate.evidence) !== canonical(challenge.evidence)) contextFail('Fresh challenge replaced original preparation identity');
|
|
61
|
+
}
|
|
62
|
+
export async function observeScopeContext(location, state, proposal, prepared, renewChallenge) {
|
|
63
|
+
const candidate = prepared ?? await prepareScopeContext(location, state, proposal);
|
|
64
|
+
let challenge = contextChallenge((state.signingChallenge ?? state.challenged).challenge, location, proposal,
|
|
65
|
+
{ allowExpired: typeof renewChallenge === 'function' });
|
|
66
|
+
const input = observationInput(location, state, proposal, challenge);
|
|
67
|
+
sameObservation(candidate, input, challenge);
|
|
68
|
+
const beforeSign = renewChallenge && (async () => {
|
|
69
|
+
challenge = contextChallenge(await renewChallenge(), location, proposal);
|
|
70
|
+
sameObservation(candidate, observationInput(location, state, proposal, challenge), challenge);
|
|
71
|
+
return { challenge: challenge.challenge, maximumExpiresAt: Date.parse(challenge.expiresAt) };
|
|
72
|
+
});
|
|
73
|
+
const facts = candidate.facts;
|
|
74
|
+
const observed = await attestScopeFacts(input, { repositoryRoot: location.root, facts,
|
|
75
|
+
snapshotDigest: facts.snapshotEvidence.snapshotDigest }, beforeSign ? { beforeSign }
|
|
76
|
+
: { maximumExpiresAt: Date.parse(challenge.expiresAt) });
|
|
77
|
+
if (!observed.attestation || observed.attestation.challenge !== challenge.challenge
|
|
78
|
+
|| canonical(observed.attestation.importContexts) !== canonical(challenge.importContexts)
|
|
79
|
+
|| observed.attestation.contextRevisionDigest !== proposal.proposalDigest
|
|
80
|
+
|| Date.parse(observed.attestation.expiresAt) > Date.parse(challenge.expiresAt)) contextFail('Context candidate requires its actual purpose-bound original S proof');
|
|
81
|
+
const after = await inspectContextEvidence(location, challenge.importContexts, challenge.evidence.map(file => file.path));
|
|
82
|
+
if (canonical(after) !== canonical(candidate.evidence)) contextFail('Build evidence changed while observing its actual imports');
|
|
83
|
+
const core = { schemaVersion: 'entrorove.scope-context-attestation/1.0', challengeId: challenge.challengeId,
|
|
84
|
+
proposalDigest: proposal.proposalDigest, scopeAttestation: observed.attestation };
|
|
85
|
+
return { ...core, signature: sign(null, Buffer.from(canonical(core)), location.key).toString('base64url') };
|
|
86
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export const SCOPE_CONTEXT_SOURCE_FILES = [
|
|
2
|
+
'scope-context-client.mjs', 'scope-context-observer.mjs', 'scope-context-observation.mjs', 'scope-context-remote.mjs',
|
|
3
|
+
'scope-context-state.mjs', 'scope-context-wire.mjs', 'scope-context-journal.mjs', 'scope-context-release.mjs',
|
|
4
|
+
]
|
|
5
|
+
export const scopeContextReleaseNote = {
|
|
6
|
+
zh: '新增首次范围门禁前的构建上下文纠正:原账号审核真实配置和构建证据,原 S 签名完整路径快照,通过服务挑战追加上下文权威记录;保留原 flow、绑定、旧上下文和失败历史,不授予写入或完成权限。',
|
|
7
|
+
en: 'Add build-context recovery before the first scope gate: original owner review of actual configuration and build evidence, original S proof of all target paths, and challenge-bound append-only context authority. Preserve the original flow, binding, contexts and failures without granting writes or completion.',
|
|
8
|
+
}
|