@entrorove/skill 0.1.67 → 0.1.69

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.
@@ -1,8 +1,15 @@
1
1
  {
2
2
  "schemaVersion": "entrorove.release-state/1.0",
3
- "version": "0.1.67",
4
- "digest": "d9a7da983f154ca0bfdd449911ae3c5e7e3af99e8dfb6ccd8eb9392c179f9e34",
3
+ "version": "0.1.69",
4
+ "digest": "4302b1f59039183c75228114755903be6ee5974bfdb95b6f7f72596f1039ff58",
5
5
  "files": {
6
+ "scope-context-client.mjs": "a21cfe75b3e13a5c5c0619cf14c84c579289d98221c6e280019dbecebfb444b9",
7
+ "scope-context-observer.mjs": "533d5096fd7f17ec255b2a7b308162e093179c1bb1f1db976aef072b8ddae76f",
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-release.mjs": "32238648219cd35a9b2c4bc01784d2150af57df16da2975fd93e94ab4f3e6065",
6
13
  "cloud-task-images.mjs": "a260a94b6b1b47df97a8cc8657dfdce1fd37ec752f1cc2bad2542eaa28622bdb",
7
14
  "model-images.mjs": "ab85ac0c44d857c1f460de3e9c06eb1d37b57688b4a6061405c0a44ae4d40bd7",
8
15
  "model-images.d.mts": "f1506cfb8ad287869f92f4d9074c7c759c6c28b182aeb325dd5f22a38926f24c",
@@ -19,7 +26,7 @@
19
26
  "local-mutation-finder-observation.mjs": "438dd33e62e03e02b55897a28b3ba59d12734b6e5142525b299f77c21537280b",
20
27
  "local-finder-store.mjs": "227191c52174386ace6391e072b78a6e4cc658a6d9dd37036ffd7e97bbf4336a",
21
28
  "local-finder-plist.mjs": "c83ddab2375a54d612d395a5518db8ae05212437d82bf3f8b76930a8859c8481",
22
- "connected-cli.mjs": "79c3359303957a9ebb8987e3dfb181f189d380fa02ef4462683b786aedfc7802",
29
+ "connected-cli.mjs": "29ab700f6a308adad5f3984bf9dd2734755a29fbd0e963e630222565846b5942",
23
30
  "local-approved-process.mjs": "442856df788e63f38757439ba0657d1c689aaf797631a955fae3dd639e844e6d",
24
31
  "local-approved-supervisor.mjs": "87142a4c13d27c8265cc1fd7fc9088988da9bbb02134164e1a7c5417da926ac7",
25
32
  "local-mutation-consumption.mjs": "1b033655f817ec576410b7f91f1640b8651f3cff0668154fb8e6e14e7b31d8f4",
@@ -30,16 +37,16 @@
30
37
  "workflow-observation-runner.mjs": "3eb8280ec7abffcb30398e3f4e5f7d0ec3df4385fa720f188ed83757b87cd977",
31
38
  "workflow-observation-state.mjs": "a525046df9b3de75b10d2bf35c2b6d7719f12a647e4aee1f1e85dbdbfb167321",
32
39
  "workflow-observation-wire.mjs": "df0d5e4f8fde0be8bf06c6c4590cd158b4da05ebe6ef3169d2366db706f3327f",
33
- "local-preserved-mutation-protection.mjs": "5186a2f682e66c6828d1504ee074554cbae0fda58a5f446fbadfb868e1682dae",
40
+ "local-preserved-mutation-protection.mjs": "289bf58933818ff13b217d0d75afd0b81cc59bc09b4ea88f50a2ab900e9cf1c2",
34
41
  "local-preserved-mutation-signer.mjs": "2b0771cbdd18ba00267aa441b7892cd04feab9f8543ae5e2703430b1e580747f",
35
42
  "local-preserved-mutation-state.mjs": "337a172b2d0a03b0d5a89b8483afdd9a043a4999fe38f87679633c98c450126b",
36
43
  "local-preserved-mutation-wire.mjs": "6768ce5713d70f7c0bd05f2286bc4b32cd9b8bb1d3c8b9cc7a451cb9b176824d",
37
44
  "local-delegated-modify-analysis.mjs": "f87148ddb023b79e241ca97db582991da8d0e1a51b26b1d9bc2799a76efd7297",
38
- "mutation-client.mjs": "da09b2aa301da8cbc7b830a3dfe1fbf2617798ae26e4ccddea802443a8253527",
45
+ "mutation-client.mjs": "8f1066db3246f7639dd0b557e7b2c6175181e52f9087146e218d0912f791808e",
39
46
  "cloud-mutation-authority.mjs": "c7226e882a4f3be4d2f55728f515d5a815c0aa1f21aa5e4689314e6e6a8c66a2",
40
47
  "ide-code-mode.mjs": "f8ba4de33632ab4c6df52dab52f392414b4632c7e94b218b8065677970c075c7",
41
- "ide-command.mjs": "dbdb4cbf8e870c93a746ca176cbbdeffc0458de1293583d3eb9af4c256541370",
42
- "ide-hook.mjs": "f2a00be9293ce13ba8b8547142744a7edc43d4e2e82727e9f7923ba79a244d75",
48
+ "ide-command.mjs": "b3c008816f53e3cd3aa97bc792baf0b7fc068e839b150bd2cfc6cb06d17a6825",
49
+ "ide-hook.mjs": "688e39193575e20f833a4f9e8f0975351d03869452acd46c8860e86ce05bccdc",
43
50
  "ide-install.mjs": "1c80e191ddc2ac8789f0c71edc7bc8c3c8cea6bfab537cdf6baffa4a6ce3419c",
44
51
  "ide-session.mjs": "5277a6ea3445bfa9b2e28847372d963da77787d472d0414c0e253d4fe29f74ec",
45
52
  "break-glass.mjs": "6ec9f97c5d68bb33121b2374c06b9d4c8eb3419b52d00849fec7124bc63e4582",
@@ -53,11 +60,11 @@
53
60
  "local-scope-import-expressions.mjs": "20f1e065582c68d2334e0dfaa130a559ff19886a57f9038dc569f65993bb06c8",
54
61
  "local-discipline-contracts.mjs": "25d2bdbcb2698a1927ce5ef43e33052ed90bfe7dbc7c6a708f2bfd4a258609fd",
55
62
  "local-discipline-contracts.d.mts": "defc684c78dc88afa1c54340ab4a01ae36db7aa11257cbe1f5cd323f608c78c4",
56
- "local-discipline-gate.mjs": "0b85dbdc4c15c5183d821ef4b50c48c59c652801eeb8072e7241e442a516f252",
63
+ "local-discipline-gate.mjs": "f80c560a4eb7c153e1637d072f0a6b4e13d4caba745317a01ff7f9b5e9143f69",
57
64
  "local-discipline-native.mjs": "8b99b5ce951cab3c1426428ad807650c61c0ffb2c346d747b73b99057b382049",
58
65
  "local-discipline-operations.mjs": "9fcb7b8889b7718d42e1d37936485d8198d5017d405e0cdbbabdbbd12fcc9d48",
59
- "local-discipline-repository.mjs": "ca997be4289180600cb97ba2938b6b99210e5d5d5317374b130a886cb712d624",
60
- "local-discipline-snapshot.mjs": "8fd35b2cfbece8f64579f144f589a66dec9b6022d50fe931c4c1f886cb83134d",
66
+ "local-discipline-repository.mjs": "748f691ad65366a68f2a7f8106a95b223a3027d3ff86481a111b27385e9aef57",
67
+ "local-discipline-snapshot.mjs": "ff1fc42a89d1eeb4977062c8698f700fc4f6ad727e1ea2ed0f255d00d63f497b",
61
68
  "local-runner-discipline.mjs": "99935b1be0d660d6cd45f5facd911bf1e1203ec74953acef5f12a7ebafacffb2",
62
69
  "local-integrity.d.mts": "21357f306234bd841c0d3d90bf2d09f7663f63746f897b9f38190428ae8198b3",
63
70
  "local-equivalence-runner.mjs": "df2f406c693c4da7bb30542ec7b4d46a9336f56e9fdd263196c0f3a73d2f6e91",
@@ -66,8 +73,8 @@
66
73
  "runtime/validator-runtime-v7.0.44.d.mts": "7797edbfe2f7de24da370204dce4dfd22822a1bd80df93514fff900b98afe36f",
67
74
  "snapshot-retention.mjs": "ca46aeb36b1a5a24fe7e967031a71b9a3d33f40cb715d344402cbe0dc9c425cb",
68
75
  "snapshot-cleanup-journal.mjs": "76a9684cc95b4eb076e1298d78a9dff37948b00d9607b8f546c599072d3ed331",
69
- "IDE-EXECUTION.md": "e7e9c19f19f095f5483784bb8de1e610eb008e8e62504b4229e38a9728b89573",
70
- "REUSE-DISCIPLINE.md": "140e8eef2402d7adcae3eafce01f26965dcbd4c270af2387d4b17d37d63ed93d",
76
+ "IDE-EXECUTION.md": "1b58e8ef0c4c95606184ba24bd0b674e3f318000d4164ec40989bda5e1eb645f",
77
+ "REUSE-DISCIPLINE.md": "a2452911c2b50c4762b4a1374f1958059eb03efd59f63e1b50e1650c52b0dc98",
71
78
  "install-identity.mjs": "41b8c8d8b3e265d2057a07bf7dc98066c34d6b05c65bf7159ca9609c01ee4646",
72
79
  "package-archive.mjs": "e06db8d709db8710bead254ee950b78928088be01c58dcea383beaa5eb574e59",
73
80
  "package-replacement.mjs": "02ca3fa4ada2addc479f8cb1b8099cd1b574adfeaa2f3c8ecf612ac2cb9127d3",
@@ -136,19 +143,19 @@
136
143
  "local-autocoord17-waits.mjs": "2b0a713987822548a94e1ed3a9a891532db45383797dfc5d5bc8d1e35593cf25",
137
144
  "local-validator-isolation17.mjs": "48e94604e28b8fddd567dfb35ff60b73fd094a5803bd49f076388b7f310f92aa",
138
145
  "local-calctool-composition17.mjs": "ac89fcb41ab0d0d9b47c1b5696945281b0894eb064820775e36a011c76314e6a",
139
- "cli.mjs": "14c0c49f06bf209e5034a69b3e81a8458154e92870ce6aeddd1069d568c00837",
146
+ "cli.mjs": "c1fc6c58c10f00189de93ddaa8cbe4f889c62cc16c8c45d55c7b4a1498eead8e",
140
147
  "ide-selection.mjs": "e11e2b363c06444f1dcb4cdab1eaa0eb748a379b84354e0e71fd9c2dc79a4815",
141
148
  "ide-exit.mjs": "39d60a15b1517d402c208d22a17033976e43733be8a10dc6da386837c59b37b2",
142
149
  "install-cleanup.mjs": "8a8e1a7dfe37427f86cd4d6e317890d0829894a9949d4216674a716b36edbc54",
143
150
  "review-client.mjs": "3491eef68ed533174b31db3c53febb6519b8f088f71a9964644714a9a4c03c77",
144
151
  "version.mjs": "85284d4cd5e3314b449e6ae124243f96397bcc274817b5983a79cfdd903d46fd",
145
- "SKILL.md": "b39010bc22b517ad24f706d843823c2dfa93eb08fc5de055d30b7cc5fb079cea",
146
- "CAPABILITY-MAP.md": "e64d1411526413d64b89142b3105e8e5bf25b3bc5b1a6ffa217b9ec93f1b58ae",
152
+ "SKILL.md": "4722190a3110d40ab7b18dcdcdf53bd6b378f5dd6015c7e6855773456d236198",
153
+ "CAPABILITY-MAP.md": "517809bb20750e5de89b2dab5705c902a27fa68cf4f3f392a5d8cf2f19818888",
147
154
  "AGREEMENT.md": "f93a68e92c457200dd024610e65f74e478b8f60860f951da818b70561f1b9bf8",
148
155
  "DELIVERY-BOUNDARIES.md": "cb23ce71b2197085c8441ba7c5b6c05fb21f2a954bf66b4d60cfef8b15895b8b",
149
- "package.json": "04be10568ee6bf09d6910ed1e434df2f5247ce2aefe9a5b84f5bbe10def6e96c",
156
+ "package.json": "68c2b335cd192d783a516de6b5449e284e16a1c3eb4adb4e7717f5d002282dcc",
150
157
  "manifest.json": "ab06e307795bc9da5add926752b6c4dbdaf18625090261a035aa356a679c504f",
151
- "release.mjs": "4466d54bee56b80561e46d79cf4f46ee07c27c45e7a8b2727583d1d0946ea8d8",
158
+ "release.mjs": "575204085e0595cc7073a78f321d8c9243cd2c0910a6d15951efe8d93ba77512",
152
159
  "local-cli.mjs": "058ac9a4653bc12e0d031b72034ebfe6a72b91b9b23353b9fee04881c7d2e098",
153
160
  "local-state-lock.mjs": "1dbf64264642a0851faf043e07ee9f66d2ad0508e9f799b0626246e42fae893e",
154
161
  "local-execution.mjs": "721ed7d29bbe4ce6d088909cd84ffc440978c3c9eb0946c49a4281ee685fe3aa",
@@ -187,7 +194,7 @@
187
194
  "local-scope-candidate.mjs": "8f0bd9606e70d4a0ebacdd3cd600ec3afed85e2bb3e1760aa1144cf55d4e028a",
188
195
  "local-scope-context.mjs": "79753abfc6c76089d17f003a1be537dfaea10d6731c542f7fc53f2a9996ed164",
189
196
  "local-scope-files.mjs": "db8b3baf8118c6cfd5525cbc008e054f9f33390b9ffce5ba72ee986b832f33e3",
190
- "local-scope-repository.mjs": "55f130f7c54a378cb12ab9b81c07b14bf17f96a8d994314b0c8f35803bbdca1c",
197
+ "local-scope-repository.mjs": "df584d45473353a19d9b5238c814456362f3004c9db183fca66f64c1fa86ec34",
191
198
  "local-scope-create-require.mjs": "6b6a209bfcad8fe1398e99c5c8cc3af189c120b9c38e244a73dd1a99c3d91295",
192
199
  "local-scope-require-resolution.mjs": "b24596462c8776cbefa6f0a74749d665aa928d1643c68d44798eb93e2dd5ad42",
193
200
  "local-scope-git.mjs": "53bbbb6c4795db711b5bc164591a6ad79a561427da046d6bbe997dae6eb82829",
@@ -213,21 +220,21 @@
213
220
  "local-budget-git-system-attributes.mjs": "367a4e5a88490c4d4c3717bc893a271970fe70d7705f0c1c72d6f76a442d5d21",
214
221
  "runtime/git-native-linux-v1.mjs": "cf5cb91426a105e62c0f07a8a230dec592dba46f85a3f708b4c4e8cfcd1126c6",
215
222
  "runtime/git-native-darwin-v1.mjs": "f88aab72dc86f94eb1115784872957cb8ed0f74205ae70e1ecd1939e7790e310",
216
- "local-scope-signature.mjs": "c4c1551c66bb276bf44c66d8e96f3cacc6edac48f6599ad964cd67f5e18110ac",
223
+ "local-scope-signature.mjs": "99b7d9e563d897c1f1bcf70894cd6370dd41ddf9a136c20822083481ef706fca",
217
224
  "local-scope-config-imports.mjs": "a399407227bbdd14468633bb6d25586df7c6a30a1ef0d1a80ab7c7b499d3fadf",
218
225
  "local-scope-config-extends.mjs": "3ab4150b846b247e9e0851221123f220c5574699af651830e751f026ab33659e",
219
226
  "local-scope-snapshot.mjs": "c0f851470b98863a1d187825ed61ee6072d1c057b178fdc85ae29af02a3b250f",
220
227
  "local-scope-state.mjs": "8b600a91fc0068d7a8c0bb752ddba7ed30ada93daafb118d6cba2368fd94cb27",
221
228
  "local-scope-workspaces.mjs": "a44c34537e5ed2dcaf193a985e5bc05957989fbb160a650f9e37ba7d66eb2de8",
222
229
  "local-task-routing.mjs": "6e2e506b2fb0e2e8d8c5147d7df32849b57a4e94a23634f01a355d45735858e4",
223
- "remote-client.mjs": "d1fdc4a65fb6d7f79af0bf5a6551319386f1127a0632927fd11600a178d41769",
230
+ "remote-client.mjs": "d30fd61fab3171a9e41546706a57ae372786d20ea9e9c01cad39d9863c156b40",
224
231
  "cloud-task-client.mjs": "603a7de8e1d56a77588f08f7d1ae93685b553b40815e268d7bd17018eb767c37",
225
- "scope-runner-client.mjs": "2afcbb8bc8a26d03f26787cb2ffd9994c4377757d16d54aa0c83752a29e833ea",
232
+ "scope-runner-client.mjs": "b85999bca05efd804325f97b6e5704623ac3fcf751c6f9760717a23f40661ad1",
226
233
  "scope-amendment-client.mjs": "64a38deddc2dbfae543fead2cff8c9c78771b576391cc903aa58db925a138ad7",
227
- "scope-amendment-state.mjs": "ad82af0ff06e4969f733328a68d18e1ff3553b8ed93400c19963744083918ab9",
234
+ "scope-amendment-state.mjs": "922c4fd5a71101651d40fdb11f94f09c904cc244ff2574ae6b6ee004448aad06",
228
235
  "scope-amendment-wire.mjs": "3c4823e23bbdf330616bb675f07f9fcad7423266bd50b92e1134d226060e9b83",
229
236
  "scope-amendment-remote.mjs": "15a0b3126248f3101a52e3d7742f9a816dd3d8e58f21bac33e99e810e86cc4fd",
230
- "scope-amendment-observer.mjs": "473f08d66ebd35d87db7e651c0521d1d4bdb6fa337afaedb241bcf9c6289d9d3",
237
+ "scope-amendment-observer.mjs": "de796f2aca2f3bc7f33ae3323b07d98096c0f16b1ffde70e3055610d70d18020",
231
238
  "scope-amendment-mutation.mjs": "fa24191df290efad29d41eca3d1a081981fefde02b7dc4a11c75c6118a69106e",
232
239
  "scope-amendment-reference.mjs": "0537e53a1bea4b695f4804c5051261778c88f05b1ae4aff86c709dcfe83aa148",
233
240
  "native-client.mjs": "6f5575909bae9daba643287f876ffa0f9ff1c53a367b32a40145d740456d6605",
@@ -260,7 +267,7 @@
260
267
  "workflow-local-request.mjs": "4e24c543ce386292a87dc9cd41f90d23375f12079cacffc515c8cd01fd571780",
261
268
  "task-message-entry.mjs": "31d10056cb905237cd5649e8eb067009ff1612ec5dc1061e0373209fbc0b646a",
262
269
  "task-message-cli.mjs": "3ca65e96c28129b3bd5cac962d106e0859a1f17df1f6a66ee543c6efc22f918d",
263
- "local-contracts.mjs": "f65c6f87ec021fa96c4e93d65d9fc2e5aca964915657e517697352d549af21a8",
270
+ "local-contracts.mjs": "0548faf3ecc4f3124c823ccd926f811580f4ba50a15bd334ff6d550e6eca013d",
264
271
  "local-contract-types.mjs": "85e71fa4dd67e351a4b67573c740bcdb1661cede53f097189f11837771e75e91",
265
272
  "local-archguard-ast.mjs": "7ff7df9dab0d98ed62983add751c80edea598bc94ef4f38ede0ebd4d41226c87",
266
273
  "local-archguard-checkpoint.mjs": "37896902520cc995720c96288e4a5ed3585952b55c9c35be281f91fa754c71ec",
@@ -288,7 +295,7 @@
288
295
  "local-calctool-runtime.mjs": "9070b6900d1782bf77357fea1cc522bf796898d56929f96d7cb935b3036ac82f",
289
296
  "local-calctool-storage.mjs": "4c3f352847aeb368dea1247759a1055beeab25534adf25b6e7323196d76fd684",
290
297
  "local-mutation-files.mjs": "087b00e8424a135e783eb432271012a71e55eeb4a5e30119490d1bc0b2160320",
291
- "local-mutation-snapshot.mjs": "f9077539680fb8d3ff33a962657756a8fe6afa8409b6191334509534216ebfe8",
298
+ "local-mutation-snapshot.mjs": "69c0ff0b67b2e6913b1d9f8247bf48c31d62f4f5ae1668c573a0ade06c01d105",
292
299
  "local-mutation-audit.mjs": "5a30ee3446f632e032ffcfe46bcd97d6dfc0f099a76ea5185c3f9a9118c4f6cb",
293
300
  "local-mutation-wire.mjs": "6d00400e531c693c3e8bfd0c2a24fcc486127f84aafc56ee450dcec7f534eb05",
294
301
  "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-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',
@@ -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.69",
4
+ "date": "2026-10-20",
5
+ "zh": "新增首次范围门禁前的构建上下文纠正:原账号审核真实配置和构建证据,原 S 签名完整路径快照,通过服务挑战追加上下文权威记录;保留原 flow、绑定、旧上下文和失败历史,不授予写入或完成权限。",
6
+ "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."
7
+ },
8
+ {
9
+ "version": "0.1.68",
10
+ "date": "2026-10-20",
11
+ "zh": "修复大目录扫描的调用栈溢出:逐项收集完整目录清单,保留忽略文件摘要、符号链接边界、原范围与签名及前后扫描变化拒绝;原流程可在标准升级后重试。",
12
+ "en": "Fix call-argument overflow in large repository scans by collecting every inventory path individually. Preserve ignored-file hashes, symlink boundaries, original scope and signatures, and inventory-drift refusal; retry the original flow after a standard managed upgrade."
13
+ },
2
14
  {
3
15
  "version": "0.1.67",
4
16
  "date": "2026-10-19",
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,134 @@
1
+ import path from 'node:path';
2
+ import { randomUUID, sign } from 'node:crypto';
3
+ import { canonical, sha256 } from './local-integrity.mjs';
4
+ import { withStateLock } from './local-state-lock.mjs';
5
+ import { atomicMutationJson14, readMutationJson14 } from './local-mutation-files.mjs';
6
+ import { bootstrapCloudMutationAuthority } from './cloud-mutation-authority.mjs';
7
+ import { contextInput, contextFail, retainedContexts, originalContextDigest, contextChallenge } from './scope-context-wire.mjs';
8
+ import { scopeContextLocation, effectiveScopeContexts, retainContextAuthority,
9
+ readContextJournal, saveContextJournal } from './scope-context-state.mjs';
10
+ import { contextRemote } from './scope-context-remote.mjs';
11
+ import { inspectContextEvidence, observeScopeContext } from './scope-context-observer.mjs';
12
+
13
+ const schemaVersion = 'entrorove.scope-context-connection/1.0';
14
+ async function archive(location, state) {
15
+ if (!state.attemptId) return;
16
+ const file = path.join(location.directory, `${state.attemptId}-${sha256(canonical(state))}.json`);
17
+ try { if (canonical(await readMutationJson14(file)) !== canonical(state)) contextFail('Context attempt history changed'); }
18
+ catch (error) { if (error.code !== 'ENOENT') throw error; await atomicMutationJson14(file, state, { privateFrom: location.stateRoot }); }
19
+ }
20
+ async function journal(location, input) {
21
+ let state = await readContextJournal(location, input);
22
+ if (state.previous || input.action === 'status' && state.completed
23
+ || input.action === 'apply' && state.completed && !state.applied || state.rejection && !state.pending) {
24
+ await archive(location, state.previous ?? state); state = {};
25
+ }
26
+ if (!state.attemptId) {
27
+ state = { schemaVersion: 'entrorove.scope-context-journal/1.0', localBindingDigest: location.localBindingDigest,
28
+ input, attemptId: randomUUID() }; await saveContextJournal(location, state);
29
+ }
30
+ return state;
31
+ }
32
+ function proposalFor(status, input, location) {
33
+ const proposal = status.proposal;
34
+ if (!proposal || proposal.proposalId !== input.proposalId || proposal.proposalDigest !== input.proposalDigest
35
+ || ['flowId', 'runnerId', 'repositoryId', 'keyId'].some(field => proposal[field] !== location.binding[field])
36
+ || proposal.localBindingDigest !== location.localBindingDigest
37
+ || canonical(proposal.targetPaths) !== canonical(location.binding.targetPaths)
38
+ || !['pending', 'approved', 'declined'].includes(proposal.approval?.status)) contextFail('Current account has no matching original context proposal');
39
+ retainedContexts(location.binding.importContexts, proposal.importContexts); return proposal;
40
+ }
41
+ function waiting(value, flowId) {
42
+ const status = value.proposal?.approval?.status;
43
+ return { ...value, schemaVersion, status: status === 'declined' ? 'blocked' : 'needs-input', flowId,
44
+ grantsExecutionAuthority: false, claimsCompletion: false,
45
+ nextStep: value.nextStep ?? { operation: 'interaction-answer', requiresOriginalOwnerApproval: true,
46
+ interactionId: value.proposal?.approval?.interactionId, interactionDigest: value.proposal?.approval?.interactionDigest } };
47
+ }
48
+ async function liveStatus(location, state, dependencies) {
49
+ if (!state.checked) await contextRemote('checked', 'scope-runner-context-status', {
50
+ flowId: location.binding.flowId, attemptId: state.attemptId }, state, location, dependencies);
51
+ const effective = await effectiveScopeContexts(location);
52
+ if (!Number.isSafeInteger(state.checked.expectedRevision) || state.checked.expectedRevision !== (effective?.record.revision ?? 0)) contextFail('Live context revision differs from its retained original history');
53
+ if ((state.checked.effective?.revisionDigest ?? null) !== (effective?.revisionDigest ?? null)) contextFail('Live context head differs from retained signed history; recover its original apply request');
54
+ return state.checked;
55
+ }
56
+ async function review(location, state, dependencies) {
57
+ if (state.reviewed) return waiting(state.reviewed, location.binding.flowId);
58
+ const status = await liveStatus(location, state, dependencies), head = await effectiveScopeContexts(location), input = state.input;
59
+ retainedContexts(head?.record.importContexts ?? location.binding.importContexts, input.importContexts);
60
+ if (!state.proposal) {
61
+ const evidence = await inspectContextEvidence(location, input.importContexts, input.evidencePaths);
62
+ state.proposal = { schemaVersion: 'entrorove.scope-context-proposal/1.0', flowId: location.binding.flowId,
63
+ runnerId: location.binding.runnerId, repositoryId: location.binding.repositoryId, keyId: location.binding.keyId,
64
+ localBindingDigest: location.localBindingDigest, expectedRevision: status.expectedRevision,
65
+ previousDigest: head?.revisionDigest ?? originalContextDigest(location), originalImportContexts: location.binding.importContexts,
66
+ importContexts: input.importContexts, evidence, reason: input.reason, attemptId: state.attemptId };
67
+ state.signature = sign(null, Buffer.from(canonical(state.proposal)), location.key).toString('base64url');
68
+ await saveContextJournal(location, state);
69
+ }
70
+ const output = await contextRemote('reviewed', 'scope-runner-context-review', { flowId: location.binding.flowId,
71
+ proposal: state.proposal, signature: state.signature }, state, location, dependencies);
72
+ state.completed = true; await saveContextJournal(location, state); return waiting(output, location.binding.flowId);
73
+ }
74
+ async function applied(location, state) {
75
+ const effective = state.applied.contextAuthority;
76
+ const challenge = contextChallenge(state.challenged.challenge, location, state.proposal, { allowExpired: true });
77
+ if (state.applied.grantsExecutionAuthority !== false || !effective?.record
78
+ || canonical(effective.record.attestation) !== canonical(state.attestation)
79
+ || ['proposalId', 'proposalDigest', 'ownerId', 'taskDigest', 'chainDigest'].some(field => effective.record[field] !== challenge[field])
80
+ || canonical(effective.record.importContexts) !== canonical(challenge.importContexts)
81
+ || canonical(effective.record.evidence) !== canonical(challenge.evidence)) contextFail('Applied context authority differs from this exact actual candidate');
82
+ const retained = await retainContextAuthority(location, effective);
83
+ state.completed = true; await saveContextJournal(location, state);
84
+ return { schemaVersion, status: 'succeeded', flowId: location.binding.flowId, contextRevisionDigest: retained.revisionDigest,
85
+ revision: retained.record.revision, grantsExecutionAuthority: false, claimsCompletion: false, nextOperation: 'scope-connect',
86
+ nextInput: { flowId: location.binding.flowId, paths: [...location.binding.targetPaths], importContexts: retained.record.importContexts } };
87
+ }
88
+ async function apply(location, state, dependencies) {
89
+ if (state.applied) return applied(location, state);
90
+ const status = await liveStatus(location, state, dependencies), proposal = proposalFor(status, state.input, location);
91
+ if (proposal.approval.status !== 'approved') {
92
+ state.completed = true; await saveContextJournal(location, state); return waiting(status, location.binding.flowId);
93
+ }
94
+ state.proposal = proposal; await saveContextJournal(location, state);
95
+ if (!state.challenged) await contextRemote('challenged', 'scope-runner-context-challenge', { flowId: location.binding.flowId,
96
+ proposalId: proposal.proposalId, proposalDigest: proposal.proposalDigest, attemptId: state.attemptId }, state, location, dependencies);
97
+ contextChallenge(state.challenged.challenge, location, proposal);
98
+ if (!state.attestation) {
99
+ state.attestation = await observeScopeContext(location, state, proposal); await saveContextJournal(location, state);
100
+ }
101
+ await contextRemote('applied', 'scope-runner-context-apply', { flowId: location.binding.flowId,
102
+ proposalId: proposal.proposalId, proposalDigest: proposal.proposalDigest, attestation: state.attestation }, state, location, dependencies);
103
+ return applied(location, state);
104
+ }
105
+ async function run(location, input, dependencies) {
106
+ const state = await journal(location, input);
107
+ if (state.pending) await contextRemote(state.pending.stage, state.pending.operation, state.pending.input, state, location, dependencies);
108
+ try {
109
+ if (input.action === 'review') return await review(location, state, dependencies);
110
+ if (input.action === 'apply') return await apply(location, state, dependencies);
111
+ const status = await liveStatus(location, state, dependencies);
112
+ state.completed = true; await saveContextJournal(location, state);
113
+ return { schemaVersion, ...status, status: 'succeeded', flowId: input.flowId, grantsExecutionAuthority: false, claimsCompletion: false };
114
+ } catch (error) {
115
+ if (!state.pending) { state.rejection ??= { code: error.code, message: error.message }; await saveContextJournal(location, state); }
116
+ throw error;
117
+ }
118
+ }
119
+ export async function runScopeContext(repositoryRoot, input, dependencies) {
120
+ try {
121
+ contextInput(input); await dependencies.install();
122
+ if (!await dependencies.agreementAccepted(dependencies.home)) return dependencies.agreementRequired(dependencies.home);
123
+ await bootstrapCloudMutationAuthority(dependencies);
124
+ const location = await scopeContextLocation(repositoryRoot, input.flowId, dependencies);
125
+ return await withStateLock(path.join(location.base, 'connection'), () => run(location, input, dependencies));
126
+ } catch (error) {
127
+ return { schemaVersion, status: 'blocked', flowId: input?.flowId,
128
+ code: error?.code?.startsWith('ENTROROVE_') ? error.code : 'ENTROROVE_SCOPE_CONTEXT_PREREQUISITE',
129
+ message: error?.code?.startsWith('ENTROROVE_') ? error.message : 'Context recovery stopped; preserve original signer, binding, journal and evidence.',
130
+ ...(error?.requestId ? { requestId: error.requestId } : {}), ...(error?.output ? { output: error.output } : {}),
131
+ ...(error?.outcomeUnknown ? { outcomeUnknown: true, nextAction: { operation: 'scope-context', method: 'GET',
132
+ requestId: error.requestId, reuseOriginalInput: true, repeatPost: false } } : {}) };
133
+ }
134
+ }
@@ -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,61 @@
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
+ export async function observeScopeContext(location, state, proposal) {
29
+ const challenge = contextChallenge(state.challenged.challenge, location, proposal);
30
+ const evidence = await inspectContextEvidence(location, challenge.importContexts, challenge.evidence.map(file => file.path));
31
+ if (canonical(evidence) !== canonical(challenge.evidence)) contextFail('Actual build configuration or loader evidence changed since review');
32
+ if (!state.snapshotId) { state.snapshotId = `context-${randomUUID()}`; await saveContextJournal(location, state); }
33
+ const input = { repositoryRoot: location.root, home: location.home, flowId: challenge.flowId, stepId: challenge.stepId,
34
+ snapshotId: state.snapshotId, paths: [...location.binding.targetPaths], importContexts: challenge.importContexts,
35
+ contextRevisionDigest: proposal.proposalDigest, contextEvidence: challenge.evidence,
36
+ signerConfigPath: location.signerConfigPath, ownerId: challenge.ownerId,
37
+ task: challenge.task, taskDigest: challenge.taskDigest, chainDigest: challenge.chainDigest,
38
+ repositoryId: challenge.repositoryId, challenge: challenge.challenge };
39
+ if (!state.snapshot) {
40
+ if (state.snapshotStarted) contextFail('Interrupted context snapshot must be inspected before another observation; preserve its files');
41
+ state.snapshotStarted = true; await saveContextJournal(location, state);
42
+ try { state.snapshot = await snapshotPlan(input); }
43
+ catch (error) { delete state.snapshotStarted; await saveContextJournal(location, state); throw error; }
44
+ await saveContextJournal(location, state);
45
+ }
46
+ const verified = await snapshotVerify(input);
47
+ if (verified.verified !== true || verified.receipt.snapshotDigest !== state.snapshot.snapshotDigest) contextFail('Actual context candidate snapshot did not verify');
48
+ const snapshot = await readScopeSnapshot(input, location.root);
49
+ const facts = await collectScopeFacts(location.root, input.paths, undefined, snapshot.known, input);
50
+ facts.snapshotEvidence = await verifyFreshScopeSnapshot(input, location.root, facts);
51
+ const observed = await attestScopeFacts(input, { repositoryRoot: location.root, facts,
52
+ snapshotDigest: facts.snapshotEvidence.snapshotDigest }, { maximumExpiresAt: Date.parse(challenge.expiresAt) });
53
+ if (!observed.attestation || canonical(observed.attestation.importContexts) !== canonical(challenge.importContexts)
54
+ || observed.attestation.contextRevisionDigest !== proposal.proposalDigest
55
+ || Date.parse(observed.attestation.expiresAt) > Date.parse(challenge.expiresAt)) contextFail('Context candidate requires its actual purpose-bound original S proof');
56
+ const after = await inspectContextEvidence(location, challenge.importContexts, challenge.evidence.map(file => file.path));
57
+ if (canonical(after) !== canonical(evidence)) contextFail('Build evidence changed while observing its actual imports');
58
+ const core = { schemaVersion: 'entrorove.scope-context-attestation/1.0', challengeId: challenge.challengeId,
59
+ proposalDigest: proposal.proposalDigest, scopeAttestation: observed.attestation };
60
+ return { ...core, signature: sign(null, Buffer.from(canonical(core)), location.key).toString('base64url') };
61
+ }
@@ -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-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
+ }
@@ -0,0 +1,60 @@
1
+ import { canonical } from './local-integrity.mjs';
2
+ import { buildInvocation, invokeRemoteResult } from './remote-client.mjs';
3
+ import { requestTransport, parseTransportResponse } from './remote-transport.mjs';
4
+ import { ideClientHeaders } from './ide-presentation.mjs';
5
+ import { acknowledgeAutomaticFeedback, queryAutomaticFeedback, verifyAutomaticFeedback } from './automatic-feedback-client.mjs';
6
+ import { readInvocations } from './local-invocations.mjs';
7
+ import { saveContextJournal } from './scope-context-state.mjs';
8
+ import { contextFail } from './scope-context-wire.mjs';
9
+
10
+ const unknown = requestId => Object.assign(new Error('Context recovery outcome is unknown; query its original request with GET only'),
11
+ { code: 'ENTROROVE_SCOPE_CONTEXT_UNKNOWN', outcomeUnknown: true, requestId });
12
+ async function recover(pending, dependencies) {
13
+ try {
14
+ const origin = dependencies.apiOrigin(), token = await dependencies.readCredential(dependencies.home);
15
+ const response = await requestTransport(origin, `/api/skill/status/${pending.requestId}`, {
16
+ headers: { authorization: `Bearer ${token}`, ...ideClientHeaders() } });
17
+ const result = parseTransportResponse(response, 'original context recovery status');
18
+ if (result?.output?.requestId !== pending.requestId || !response.ok || ['running', 'pending'].includes(result.output.status)) throw unknown(pending.requestId);
19
+ if (pending.operation !== 'scope-runner-context-status' || result.feedback) {
20
+ result.feedback ??= await queryAutomaticFeedback(pending.requestId, dependencies);
21
+ verifyAutomaticFeedback(result.feedback, pending.requestId, pending.requestId);
22
+ result.feedback = await acknowledgeAutomaticFeedback(result.feedback, origin, token, ideClientHeaders());
23
+ }
24
+ return { response, result };
25
+ } catch { throw unknown(pending.requestId); }
26
+ }
27
+ async function notSent(pending, home) {
28
+ try {
29
+ const rows = (await readInvocations(home)).filter(row => row.kind === 'remote' && row.requestId === pending.requestId);
30
+ return !rows.length || rows.at(-1).event === 'not-sent';
31
+ } catch (error) { return error.code === 'ENOENT'; }
32
+ }
33
+ export async function contextRemote(stage, operation, input, state, location, dependencies) {
34
+ const requestId = buildInvocation(operation, input).requestId; let response, result;
35
+ if (state.pending) {
36
+ if (state.pending.stage !== stage || state.pending.requestId !== requestId || state.pending.operation !== operation
37
+ || canonical(state.pending.input) !== canonical(input)) contextFail('Recover the original context POST before another operation');
38
+ ({ response, result } = await recover(state.pending, dependencies));
39
+ } else {
40
+ state.pending = { stage, operation, input, requestId }; await saveContextJournal(location, state);
41
+ try { ({ response, result } = await invokeRemoteResult({ operation, input }, dependencies)); }
42
+ catch (error) {
43
+ if (await notSent(state.pending, dependencies.home)) {
44
+ delete state.pending; await saveContextJournal(location, state);
45
+ throw Object.assign(new Error('Context request was not transmitted; repair its prerequisite and reuse the original input'),
46
+ { code: 'ENTROROVE_SCOPE_CONTEXT_NOT_SENT', knownBeforeTransmission: true, requestId });
47
+ }
48
+ throw unknown(requestId);
49
+ }
50
+ }
51
+ if (!result?.output || result.output.requestId !== requestId) throw unknown(requestId);
52
+ if (result.feedback) state.feedback = result.feedback;
53
+ if (!response.ok || !['succeeded', 'needs-input'].includes(result.output.status)) {
54
+ state.rejection = { requestId, output: result.output }; delete state.pending; await saveContextJournal(location, state);
55
+ throw Object.assign(new Error('Original context request was rejected; preserve its exact evidence and history'),
56
+ { code: result.output.code ?? 'ENTROROVE_SCOPE_CONTEXT_REJECTED', requestId, output: result.output });
57
+ }
58
+ state[stage] = result.output.result ?? result.output; delete state.pending; await saveContextJournal(location, state);
59
+ return state[stage];
60
+ }