@entrorove/skill 0.1.51 → 0.1.53

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CAPABILITY-MAP.md +14 -2
  2. package/CHANGELOG.md +12 -0
  3. package/DELIVERY-BOUNDARIES.md +4 -2
  4. package/IDE-EXECUTION.md +25 -3
  5. package/SKILL.md +8 -4
  6. package/cli.mjs +4 -6
  7. package/cloud-mutation-authority.mjs +96 -0
  8. package/connected-cli.mjs +20 -0
  9. package/ide-command.mjs +1 -1
  10. package/ide-hook.mjs +24 -10
  11. package/ide-results.mjs +8 -6
  12. package/ide-session.mjs +44 -1
  13. package/local-approved-plan.mjs +3 -21
  14. package/local-approved-process.mjs +54 -0
  15. package/local-approved-supervisor.mjs +99 -0
  16. package/local-cli.mjs +13 -2
  17. package/local-contracts.mjs +2 -0
  18. package/local-delegated-modify-analysis.mjs +232 -0
  19. package/local-discipline-actions.mjs +2 -0
  20. package/local-discipline-analysis.mjs +11 -5
  21. package/local-discipline-gate.mjs +3 -1
  22. package/local-discipline-repository.mjs +7 -4
  23. package/local-error.mjs +3 -0
  24. package/local-execution.mjs +1 -1
  25. package/local-mutation-authority.mjs +23 -5
  26. package/local-mutation-batch.mjs +1 -0
  27. package/local-mutation-binding.mjs +14 -5
  28. package/local-mutation-consumption.mjs +93 -0
  29. package/local-mutation-pass-store.mjs +6 -4
  30. package/local-mutation-wire.mjs +21 -4
  31. package/local-preserved-mutation-protection.mjs +51 -0
  32. package/local-preserved-mutation-signer.mjs +81 -0
  33. package/local-preserved-mutation-state.mjs +96 -0
  34. package/local-preserved-mutation-wire.mjs +49 -0
  35. package/local-scope-import-expressions.mjs +80 -0
  36. package/local-scope-repository.mjs +32 -21
  37. package/local-typescript-function-reference.mjs +98 -0
  38. package/manifest.json +1 -1
  39. package/mutation-client.mjs +290 -0
  40. package/package.json +22 -3
  41. package/release-state.json +49 -30
  42. package/release.mjs +25 -0
  43. package/releases.json +12 -0
  44. package/remote-client.mjs +2 -1
  45. package/reuse-discipline-release.mjs +3 -0
  46. package/workflow-observation-client.mjs +44 -0
  47. package/workflow-observation-connection.mjs +35 -0
  48. package/workflow-observation-remote.mjs +84 -0
  49. package/workflow-observation-runner.mjs +87 -0
  50. package/workflow-observation-state.mjs +36 -0
  51. package/workflow-observation-wire.mjs +69 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@entrorove/skill",
3
- "version": "0.1.51",
3
+ "version": "0.1.53",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "entrorove": "cli.mjs"
@@ -38,6 +38,13 @@
38
38
  "local-mutation-snapshot.mjs",
39
39
  "local-mutation-audit.mjs",
40
40
  "local-mutation-wire.mjs",
41
+ "local-preserved-mutation-protection.mjs",
42
+ "local-preserved-mutation-signer.mjs",
43
+ "local-preserved-mutation-state.mjs",
44
+ "local-preserved-mutation-wire.mjs",
45
+ "local-delegated-modify-analysis.mjs",
46
+ "mutation-client.mjs",
47
+ "cloud-mutation-authority.mjs",
41
48
  "local-mutation-binding.mjs",
42
49
  "local-mutation-pass-store.mjs",
43
50
  "local-mutation-authority.mjs",
@@ -132,6 +139,7 @@
132
139
  "local-scope-candidate.mjs",
133
140
  "local-scope-context.mjs",
134
141
  "local-scope-files.mjs",
142
+ "local-scope-import-expressions.mjs",
135
143
  "local-scope-repository.mjs",
136
144
  "local-scope-signature.mjs",
137
145
  "local-scope-config-imports.mjs",
@@ -212,6 +220,7 @@
212
220
  "ide-queue.mjs",
213
221
  "local-discipline-actions.mjs",
214
222
  "local-discipline-analysis.mjs",
223
+ "local-typescript-function-reference.mjs",
215
224
  "local-discipline-batch.mjs",
216
225
  "local-discipline-contracts.mjs",
217
226
  "local-discipline-gate.mjs",
@@ -230,10 +239,20 @@
230
239
  "IDE-EXECUTION.md",
231
240
  "REUSE-DISCIPLINE.md",
232
241
  "DELIVERY-BOUNDARIES.md",
233
- "reuse-discipline-release.mjs"
242
+ "reuse-discipline-release.mjs",
243
+ "connected-cli.mjs",
244
+ "local-approved-process.mjs",
245
+ "local-approved-supervisor.mjs",
246
+ "local-mutation-consumption.mjs",
247
+ "workflow-observation-client.mjs",
248
+ "workflow-observation-connection.mjs",
249
+ "workflow-observation-remote.mjs",
250
+ "workflow-observation-runner.mjs",
251
+ "workflow-observation-state.mjs",
252
+ "workflow-observation-wire.mjs"
234
253
  ],
235
254
  "scripts": {
236
- "test": "node --test --test-concurrency=1 test/*.test.mjs",
255
+ "test": "node test/run.mjs",
237
256
  "prepublishOnly": "node release.mjs",
238
257
  "prepare:archguard": "node archguard-runtime-build.mjs",
239
258
  "check:archguard": "node archguard-runtime-build.mjs --check",
@@ -1,25 +1,44 @@
1
1
  {
2
2
  "schemaVersion": "entrorove.release-state/1.0",
3
- "version": "0.1.51",
4
- "digest": "337302626679e547236186da4653bd37c5ed8aec25bd24999920488334426587",
3
+ "version": "0.1.53",
4
+ "digest": "3508e9d78536c07403711408fe6dc6d71d137820f34d3d164c4b5898be923df5",
5
5
  "files": {
6
+ "connected-cli.mjs": "260c0fc99586c24bd4d0351a14e0744849a612ebe6f1bd7951e4fce200daf920",
7
+ "local-approved-process.mjs": "442856df788e63f38757439ba0657d1c689aaf797631a955fae3dd639e844e6d",
8
+ "local-approved-supervisor.mjs": "87142a4c13d27c8265cc1fd7fc9088988da9bbb02134164e1a7c5417da926ac7",
9
+ "local-mutation-consumption.mjs": "cd8650b9be894639ceb35af88d23c8002b4acff27afad2e64174eb21a9424cfb",
10
+ "workflow-observation-client.mjs": "5e67bc32a8625de9523498f694655c378ae34af59c4aa2f0e07efcd72347dbc0",
11
+ "workflow-observation-connection.mjs": "9235e9247b11e1d51628c1784eb1cb1e8e4b79d25ff791883722592dcf8583c0",
12
+ "workflow-observation-remote.mjs": "1e5a8b9c2b9b095242ad28a1d5ebce5944efdae74383fb20d6676b93b240c5a7",
13
+ "workflow-observation-runner.mjs": "3eb8280ec7abffcb30398e3f4e5f7d0ec3df4385fa720f188ed83757b87cd977",
14
+ "workflow-observation-state.mjs": "a525046df9b3de75b10d2bf35c2b6d7719f12a647e4aee1f1e85dbdbfb167321",
15
+ "workflow-observation-wire.mjs": "846d0b48b7799bfca227e30faea025a5a919896538f963ce886cbdb4c75c0253",
16
+ "local-preserved-mutation-protection.mjs": "95041d4f75253a153c7fd85573ba0457513ffe47a6a6bd00c4f59379b81ce580",
17
+ "local-preserved-mutation-signer.mjs": "2b0771cbdd18ba00267aa441b7892cd04feab9f8543ae5e2703430b1e580747f",
18
+ "local-preserved-mutation-state.mjs": "1ff7939d668e39ec641a7cf46a4ce3014c63f3898207cc874f21170376479671",
19
+ "local-preserved-mutation-wire.mjs": "d302bd4b115338c0d1bf69718ce2596dbceb595431ff3f57b998ea67d94cb34c",
20
+ "local-delegated-modify-analysis.mjs": "f87148ddb023b79e241ca97db582991da8d0e1a51b26b1d9bc2799a76efd7297",
21
+ "mutation-client.mjs": "8d27b267dc660510aa1406c44d4005e44b972a1260f90657de4fa0e75b7b6c3e",
22
+ "cloud-mutation-authority.mjs": "c7226e882a4f3be4d2f55728f515d5a815c0aa1f21aa5e4689314e6e6a8c66a2",
6
23
  "ide-code-mode.mjs": "f3f53357ba09727b3b597851976a24de93287c0faca5052448277d0904bb61f7",
7
- "ide-command.mjs": "86472c2f89c17e13a6fb0e41794add983400aac3e626891dbb3812e34320e229",
8
- "ide-hook.mjs": "2f00e56de1e1149f117714d5dd334196f1a3f206c3bfab541393bc0f625e0108",
24
+ "ide-command.mjs": "f2fe57312f83a11b318f1c98db51a6a47a7ff45b53f392acce32e458976bd06c",
25
+ "ide-hook.mjs": "be328cc646ea6ec5dc18e5458dd1f829897cc386d74bda0b56cbd14f53c98827",
9
26
  "ide-install.mjs": "10247efadcfeef5da001022d12080bd0f789e67fdf7862bcc65db73dda3bbe57",
10
- "ide-session.mjs": "dc256e77b03303932d354768c0e79384340a3137e7421b4ae9c869f7e58e1a3a",
27
+ "ide-session.mjs": "453b9510ab825c2927a4fae8250ee8a8eb5ac10b23cf024af84a7c5916ba53dd",
11
28
  "break-glass.mjs": "6ec9f97c5d68bb33121b2374c06b9d4c8eb3419b52d00849fec7124bc63e4582",
12
- "ide-results.mjs": "dfe0d3f773c65a9fc21056538d7005012c982ed4509bc0410d7f62813d0863fd",
29
+ "ide-results.mjs": "7ed5caf8e77cf42ae6d62cc1ed42b1639bca6069d809b90a399bec5192fb903e",
13
30
  "ide-queue.mjs": "806e716c775fd0079417027b135977c8516f47dddb0bc5ca19e32a355dab0e9e",
14
- "local-discipline-actions.mjs": "2379c08d0f49c44068f8239db7e514d75885f4606b1b88a7a36e4ff19167caca",
15
- "local-discipline-analysis.mjs": "f49e67a2eb2f19f8eb7c4226d481842b38c0f19b495ad0149cbf649baae16bb9",
31
+ "local-discipline-actions.mjs": "418c220b8c8ef59cb8092b6eb680bb75a93b9fad1a09412b1efa98a78afff11b",
32
+ "local-discipline-analysis.mjs": "e887abdd1c6d6ba59ef7323e9035528f0491e5458ca8159985ec26e1ca67a4af",
16
33
  "local-discipline-batch.mjs": "2cc90dbae55efdee0c445da399c0a9acafa92e915344c25208ebca554fc4c9e9",
34
+ "local-typescript-function-reference.mjs": "af682b479fe0d69a5ecd62232406bb8078408ec8710733cfed9ae6b059762ba5",
35
+ "local-scope-import-expressions.mjs": "6623dea5501c4dc24e12c99e0776d65650bbe752c85c9509d022ba1f61bd5111",
17
36
  "local-discipline-contracts.mjs": "6cf8a3d132fdb9074eb1441600afe7aa199df33e88a71a660d9db534c14f19e4",
18
37
  "local-discipline-contracts.d.mts": "defc684c78dc88afa1c54340ab4a01ae36db7aa11257cbe1f5cd323f608c78c4",
19
- "local-discipline-gate.mjs": "04b1ba092d7f4342a0e77cfbeb44d9634dbce9fec0c79e6a1e4b11a662d904ac",
38
+ "local-discipline-gate.mjs": "e3851157bf1d8bc86eb44212a88acd20acfc2d1152e7d87af6dc2a37afffcd6f",
20
39
  "local-discipline-native.mjs": "8b99b5ce951cab3c1426428ad807650c61c0ffb2c346d747b73b99057b382049",
21
40
  "local-discipline-operations.mjs": "9fcb7b8889b7718d42e1d37936485d8198d5017d405e0cdbbabdbbd12fcc9d48",
22
- "local-discipline-repository.mjs": "ffd31e9b2946a9784d4ab59cee5345318d2152816ce995ed5dac11efa4096bc4",
41
+ "local-discipline-repository.mjs": "b6392e02ecae333dfdc8df41f203fd69bed035d88b15b16d112ab1897b3c297c",
23
42
  "local-discipline-snapshot.mjs": "8fd35b2cfbece8f64579f144f589a66dec9b6022d50fe931c4c1f886cb83134d",
24
43
  "local-runner-discipline.mjs": "86f451de2f1e12a24f5596a29828891c1eba13cd4714ed0c18a77d66cecef934",
25
44
  "local-integrity.d.mts": "21357f306234bd841c0d3d90bf2d09f7663f63746f897b9f38190428ae8198b3",
@@ -29,9 +48,9 @@
29
48
  "runtime/validator-runtime-v7.0.44.d.mts": "7797edbfe2f7de24da370204dce4dfd22822a1bd80df93514fff900b98afe36f",
30
49
  "snapshot-retention.mjs": "4f8919fe8ec49fb4c23e080a8ad2fa3a9282bca3fffe7cf55c64e89ef316697e",
31
50
  "snapshot-cleanup-journal.mjs": "76a9684cc95b4eb076e1298d78a9dff37948b00d9607b8f546c599072d3ed331",
32
- "IDE-EXECUTION.md": "2cb952bb919261e9e420c9d83659eba013e5b1b175d80da03b50b660edfe4f31",
51
+ "IDE-EXECUTION.md": "fe8ff87dde885832b34a369985f02b567efa096ed1c1e79a0e490280c8540bf5",
33
52
  "REUSE-DISCIPLINE.md": "5b214cf313e7f715f52d54e28093a2d038f0f196ca64b15d1c49587b9d8eecf8",
34
- "reuse-discipline-release.mjs": "20ded9c21bd71b8779c454f5eba4c7c0a943ef99d94117b9bbef891d2ab6e3de",
53
+ "reuse-discipline-release.mjs": "2935898d1aa807fb982a78d7ab5cb1abe05e3c8fc945dc0909da8098872aa1ac",
35
54
  "local-final-gate16.mjs": "083aec470670e6cdb7ad2ab27b7a51b53a9ec3a8b4121cb9cbfa17d9940892c2",
36
55
  "local-final-gate16-checks.mjs": "1dd30e9666d458d8b12ca6e4975f6f0ac8450c3ea9cbecc7401ae037f66b589a",
37
56
  "local-final-gate16-worker.mjs": "344d64b6c1c5552b96960e0d8514a876a3dbfa9762ab9eb749038e8351727121",
@@ -73,25 +92,25 @@
73
92
  "local-autocoord17-waits.mjs": "2b0a713987822548a94e1ed3a9a891532db45383797dfc5d5bc8d1e35593cf25",
74
93
  "local-validator-isolation17.mjs": "48e94604e28b8fddd567dfb35ff60b73fd094a5803bd49f076388b7f310f92aa",
75
94
  "local-calctool-composition17.mjs": "ac89fcb41ab0d0d9b47c1b5696945281b0894eb064820775e36a011c76314e6a",
76
- "cli.mjs": "2f1fa353a80000ed26061feeb44a6a4ad12e32a2f49c84bfbb6c54f89f519b7b",
95
+ "cli.mjs": "74b72be1190c4ff79279a8b911a85cc654ea860574691eb79eefb5fbab4a6fbe",
77
96
  "install-cleanup.mjs": "8a8e1a7dfe37427f86cd4d6e317890d0829894a9949d4216674a716b36edbc54",
78
97
  "review-client.mjs": "3491eef68ed533174b31db3c53febb6519b8f088f71a9964644714a9a4c03c77",
79
98
  "version.mjs": "1f392147d72c40af4b03b307ea607075fb815af5174fa07e254b95fe12dbf3e7",
80
- "SKILL.md": "0d581e76d8c959ae04e091e24df5580e56d9ec9b6c1c6fa25a531a21e8b88ea4",
81
- "CAPABILITY-MAP.md": "a0f0468a098725ced52a96dd8e22bfc7d1ce7681a8446ebf7dae3696c76c3385",
99
+ "SKILL.md": "d21f5085c0a5f830d5fd8b65e3a9da1e6d15512db69a4a8daab3e94fb8738f0b",
100
+ "CAPABILITY-MAP.md": "69b2c49b111d651969dea7430f4df7950d8fdf2f0f151d8386fa04968b872ac0",
82
101
  "AGREEMENT.md": "f93a68e92c457200dd024610e65f74e478b8f60860f951da818b70561f1b9bf8",
83
- "DELIVERY-BOUNDARIES.md": "d1bb2895e23fc14bf1c76707bd1f6f03b39695501a78a0b7289dc37b099889dc",
84
- "package.json": "cdb1f686304d5d29d1feff1b1ec5b75e4e3dcff1f1da841dfb59d0502ab261e8",
102
+ "DELIVERY-BOUNDARIES.md": "9b9db50ed1bcce9e77ff6527b6bb7eaf12f3b913162ea9cb7fe90db06b393a4f",
103
+ "package.json": "6a0566be47288eba3fb8b327e19d50df62f47a90e101ff952b49cedd951c04b7",
85
104
  "manifest.json": "ab06e307795bc9da5add926752b6c4dbdaf18625090261a035aa356a679c504f",
86
- "release.mjs": "e206cb6cabbb02542317bce283f7ba674621e67765a3eacef5741f2d6b1c58b2",
87
- "local-cli.mjs": "11461e4cf4f6a8612ff275bf8296ec57ff22281156cb2c72834d3c764ba422a1",
105
+ "release.mjs": "6292dd8a4ef82c5674f4aa80a8e70059f378162162b83aae750fa55697ba90d3",
106
+ "local-cli.mjs": "41e2a737c8587cb5ce469a7661f6d14b5ea4cd073f8286822fc4dc96b67f56a1",
88
107
  "local-state-lock.mjs": "1dbf64264642a0851faf043e07ee9f66d2ad0508e9f799b0626246e42fae893e",
89
- "local-execution.mjs": "46fddd78cd954fb080c660affe90cdaa716695580427336acb820089441a8025",
108
+ "local-execution.mjs": "185f34e917440a360b3c4bafd3af245243807d964ae3820b3cffaaa2e6348cc6",
90
109
  "local-integrity.mjs": "e6d6eace80c610f3c7299d4f8644b0dc023aa9e3d8d64b26535ea7fbced248f1",
91
110
  "local-evidence-verification.mjs": "9b7dea31777505272f63616fd62af7603338f703bb1285fc565d6451715c7ce0",
92
111
  "local-formula.mjs": "706d5ec0cb2caf95a547531a81ca746fe246d4c53d902e03595a3b360e8c85af",
93
112
  "local-ledger.mjs": "2009fb68aadcd7292b72f1d0d99f378d03644be1c5b4b4150d9f6a0b3f7c15ce",
94
- "local-error.mjs": "12a4aa19fe5d57218d78c8fecb0685dd02f99155999cbbfba8da8950047638f9",
113
+ "local-error.mjs": "f01213b21d84402dc5257aaa3ae4a5fa78931a956e9b8526b1e7dbf1b20b6b5d",
95
114
  "blueprint-criterion-wire.mjs": "fb6b7dcce0b97a699e3e8968372767a3fddd83fedc750998573f789177243072",
96
115
  "blueprint-criterion-runner.mjs": "761c0e670b4b20c6bed53e5ca5d0178759505c3977ea2ed1b7223383c534bc4c",
97
116
  "local-chain-bindings.mjs": "b8eff999ccd17b53c614a3c9f5376da78fcaa8632bb3e07bc1adcceda2e75f6c",
@@ -104,7 +123,7 @@
104
123
  "local-chain-plan.mjs": "e45a9170f569c80f7e5532bbc109dbae3c24b696815316e503cb3779135be648",
105
124
  "local-chain-release-labels.mjs": "7ce5350d1062d5236f57f10e7e81713c1101463d5e7f252604ef0c2a30840bfe",
106
125
  "local-chain-results.mjs": "0455f72cad574cfef87c2c6c0928d6432bba7e5dbaff521a2b62a9575299ca10",
107
- "local-approved-plan.mjs": "825059864d4ca1e5a85d1a715ad68c3923350e1be233d4f3bb09d6f31b0143af",
126
+ "local-approved-plan.mjs": "26731b534f4c276c6235cb73bf6950943061947967a93f477f4bcd64acde72a6",
108
127
  "local-budget-renewal.mjs": "6b436358066fe33b2f6d871fc90d8e7c551edd6255efd73c0d255d0fd35d5ef8",
109
128
  "local-probe.mjs": "9b948db1de1e34c7605c4c454cd4aced66d2b57d2cf4471adbb80bcc76dee635",
110
129
  "local-budget-grants.mjs": "c5f6542f5d2c3bfe07f3ca5b5bc849bf05d886b06014f720322d530510775d3d",
@@ -122,7 +141,7 @@
122
141
  "local-scope-candidate.mjs": "8f0bd9606e70d4a0ebacdd3cd600ec3afed85e2bb3e1760aa1144cf55d4e028a",
123
142
  "local-scope-context.mjs": "79753abfc6c76089d17f003a1be537dfaea10d6731c542f7fc53f2a9996ed164",
124
143
  "local-scope-files.mjs": "4c14a5e226dd5518aeb37f199b1aa896943a66d41e5a1757a3b3fd8a79446d76",
125
- "local-scope-repository.mjs": "5bdd92729faec9b30f70d57891d0779b3cbff78b8a6a21c98240cdb62f2109d1",
144
+ "local-scope-repository.mjs": "d9d4c81c3f401c38c33b8dd7bdf8ebaf4658d1afd1cce408a7acd37f8836a6df",
126
145
  "local-scope-git.mjs": "53bbbb6c4795db711b5bc164591a6ad79a561427da046d6bbe997dae6eb82829",
127
146
  "local-scope-git-reads.mjs": "5d8a2636bab955cb325cb693db7423e69512355887ae5b5af3b8cb615f5ddad0",
128
147
  "local-git-executable.mjs": "9391d716529025b1de3ee006df658a9d765b6ef29ad24ef9b7436829318e651e",
@@ -153,7 +172,7 @@
153
172
  "local-scope-state.mjs": "8b600a91fc0068d7a8c0bb752ddba7ed30ada93daafb118d6cba2368fd94cb27",
154
173
  "local-scope-workspaces.mjs": "a44c34537e5ed2dcaf193a985e5bc05957989fbb160a650f9e37ba7d66eb2de8",
155
174
  "local-task-routing.mjs": "6e2e506b2fb0e2e8d8c5147d7df32849b57a4e94a23634f01a355d45735858e4",
156
- "remote-client.mjs": "bfb58132759a4312adc8ab33115d807c5a8d90c955aca3678e361ab9cefa84bd",
175
+ "remote-client.mjs": "0d1ec6506fe53a1e33c31c5ba19d14e30e00e85e11eaf7ff8277ea798b9f36c9",
157
176
  "cloud-task-client.mjs": "11acb1a033c94cdfbdfb177a3402ad97f6a5226f577138c8cf6395dc3ebb1a39",
158
177
  "scope-runner-client.mjs": "646ab4f80d4a8209e922fd45f40efd968f0744d9dfc03188b222c1a2e11e83b8",
159
178
  "native-client.mjs": "6f5575909bae9daba643287f876ffa0f9ff1c53a367b32a40145d740456d6605",
@@ -186,7 +205,7 @@
186
205
  "workflow-local-request.mjs": "4e24c543ce386292a87dc9cd41f90d23375f12079cacffc515c8cd01fd571780",
187
206
  "task-message-entry.mjs": "31d10056cb905237cd5649e8eb067009ff1612ec5dc1061e0373209fbc0b646a",
188
207
  "task-message-cli.mjs": "3ca65e96c28129b3bd5cac962d106e0859a1f17df1f6a66ee543c6efc22f918d",
189
- "local-contracts.mjs": "bb1df682f06782f1c8814d50fe1c455153b29f3a1a093e87dd4ab2ed5ae16e1a",
208
+ "local-contracts.mjs": "b59fcdace17b0b56117c564f8c15322465243e69adede182c5dde9204836c99c",
190
209
  "local-contract-types.mjs": "85e71fa4dd67e351a4b67573c740bcdb1661cede53f097189f11837771e75e91",
191
210
  "local-archguard-ast.mjs": "7ff7df9dab0d98ed62983add751c80edea598bc94ef4f38ede0ebd4d41226c87",
192
211
  "local-archguard-checkpoint.mjs": "37896902520cc995720c96288e4a5ed3585952b55c9c35be281f91fa754c71ec",
@@ -216,11 +235,11 @@
216
235
  "local-mutation-files.mjs": "087b00e8424a135e783eb432271012a71e55eeb4a5e30119490d1bc0b2160320",
217
236
  "local-mutation-snapshot.mjs": "f9077539680fb8d3ff33a962657756a8fe6afa8409b6191334509534216ebfe8",
218
237
  "local-mutation-audit.mjs": "5a30ee3446f632e032ffcfe46bcd97d6dfc0f099a76ea5185c3f9a9118c4f6cb",
219
- "local-mutation-wire.mjs": "465463712f638f40c87fd885932f6a9a8c1db64489bb7ca6614fb643d7a36624",
220
- "local-mutation-binding.mjs": "a1756642dd758701b476d332a48799b4af56fdd8f67aba6d46ca9bb2341b6327",
221
- "local-mutation-pass-store.mjs": "8d6b57c6d1ea3df15a794e6a4cd39497f4412a5f911b9a30b0437498f51f92c0",
222
- "local-mutation-authority.mjs": "1af7e04f545bb82df4ee91c256009d5f8d5ee71aab5a734c80d911dce6a646bb",
223
- "local-mutation-batch.mjs": "a4e9d879172e0acf79a194707ae152b4428d6fc67a837171ff115dbc00e4d6e4",
238
+ "local-mutation-wire.mjs": "7af0c585e8dd6936c0ff17f491c64a198744629f063279c31589d887ec83ae9c",
239
+ "local-mutation-binding.mjs": "4440d792453a07a375b635fa5a91db607e58162824baced5c79a9a513f4ec918",
240
+ "local-mutation-pass-store.mjs": "1edc5fcc537dfa04b8ae8b07af554d61ea5911a5da281423ad57214ccf753ad4",
241
+ "local-mutation-authority.mjs": "ebac0cc8126969bafb0aaaeacf71e05124997d5c3214f8ec32b7a4fa14569bcf",
242
+ "local-mutation-batch.mjs": "de27686b5f99a99b02f0218a3fa159e9469d6b19c595117287d6dd37a6efcb3b",
224
243
  "local-mutation-batch-receipt.mjs": "b0e6a8522867255d899e60b66677885933f6a1c4c771cbb52f84dbbbdcf5e5c2",
225
244
  "calctool-runtime-entry.mjs": "98d2bc8df38d16131fc56db0a3d4d260531ba4df412baa5ddc4b8b5c5ca99fe9",
226
245
  "calctool-runtime-build.mjs": "3c5a9bd40bc1abe02e3b6e307809eea4eaaf198e8f0db6f5d6b2583dd68a59d2",
package/release.mjs CHANGED
@@ -28,7 +28,26 @@ const coordination17SourceFiles = Object.freeze([
28
28
  'local-validator-isolation17.mjs',
29
29
  'local-calctool-composition17.mjs',
30
30
  ])
31
+ const preservedMutationSourceFiles = Object.freeze([
32
+ 'local-preserved-mutation-protection.mjs', 'local-preserved-mutation-signer.mjs',
33
+ 'local-preserved-mutation-state.mjs', 'local-preserved-mutation-wire.mjs',
34
+ 'local-delegated-modify-analysis.mjs', 'mutation-client.mjs', 'cloud-mutation-authority.mjs',
35
+ ])
36
+ const memberContinuationSourceFiles = Object.freeze([
37
+ 'connected-cli.mjs',
38
+ 'local-approved-process.mjs',
39
+ 'local-approved-supervisor.mjs',
40
+ 'local-mutation-consumption.mjs',
41
+ 'workflow-observation-client.mjs',
42
+ 'workflow-observation-connection.mjs',
43
+ 'workflow-observation-remote.mjs',
44
+ 'workflow-observation-runner.mjs',
45
+ 'workflow-observation-state.mjs',
46
+ 'workflow-observation-wire.mjs',
47
+ ])
31
48
  const sourceFiles = [
49
+ ...memberContinuationSourceFiles,
50
+ ...preservedMutationSourceFiles,
32
51
  ...REUSE_DISCIPLINE_SOURCE_FILES,
33
52
  ...FINAL_GATE16_PACKAGE_FILES,
34
53
  'local-merge-archguard-verification.d.mts',
@@ -212,6 +231,12 @@ const calctoolReleaseLabels = Object.freeze({
212
231
  })
213
232
 
214
233
  const mutationReleaseLabels = Object.freeze({
234
+ ...Object.fromEntries(memberContinuationSourceFiles.map(file => [file, {
235
+ zh: '原任务连续编辑与本地测试观察', en: 'original-task continuation and local command observation',
236
+ }])),
237
+ ...Object.fromEntries(preservedMutationSourceFiles.map(file => [file, {
238
+ zh: '保留运行时依赖的受限本地编辑授权', en: 'restricted local editing with preserved runtime dependencies',
239
+ }])),
215
240
  'local-mutation-files.mjs': { zh: '原任务短时写入授权与文件快照隔离', en: 'Original task short-lived mutation authority and file snapshot isolation' },
216
241
  'local-mutation-snapshot.mjs': { zh: '原任务短时写入授权与文件快照隔离', en: 'Original task short-lived mutation authority and file snapshot isolation' },
217
242
  'local-mutation-audit.mjs': { zh: '原任务短时写入授权与文件快照隔离', en: 'Original task short-lived mutation authority and file snapshot isolation' },
package/releases.json CHANGED
@@ -1,4 +1,16 @@
1
1
  [
2
+ {
3
+ "version": "0.1.53",
4
+ "date": "2026-10-17",
5
+ "zh": "补齐原任务受限编辑、真实写后结算与连续修改,保留未知依赖和独立验证边界;沙箱关闭后可运行原批准命令并保存本地观察。修复前置条件、断线恢复和停止循环,独立监督器约束崩溃后的子进程。本地成功不代表独立验证或交付。",
6
+ "en": "Added original-task restricted editing, real write settlement and subsequent modifications while preserving unknown dependencies and independent validation. With cloud sandbox disabled, retain actual observations of the approved command. Fixed prerequisite recovery, disconnections and Stop loops; an independent supervisor bounds child processes after CLI failure. Local success does not certify independent verification or delivery."
7
+ },
8
+ {
9
+ "version": "0.1.52",
10
+ "date": "2026-10-17",
11
+ "zh": "修复 Vue/TypeScript 的 Function 类型和真实 Vue 回调 prop 被误判为动态依赖;解析不可变 const 的有限语言模块导入,记录实际依赖与哈希。补齐 Vue 候选依赖检查;未知运行时导入报告文件、行列和原因。测试采用隔离用户目录,越界、动态执行、未知删除与原任务写入校验继续保留。",
12
+ "en": "Fixed Vue/TypeScript Function types and genuine Vue callback props being misclassified as dynamic dependencies. Resolve finite immutable const-based language imports with actual dependency hashes and inspect Vue candidate dependencies. Unbounded runtime imports report file, line, column and reason. Tests use isolated user directories while path, dynamic-execution, unknown-deletion and original-task mutation checks remain enforced."
13
+ },
2
14
  {
3
15
  "version": "0.1.51",
4
16
  "date": "2026-10-16",
package/remote-client.mjs CHANGED
@@ -37,7 +37,8 @@ function discoveredAjv() {
37
37
  export function buildInvocation(operation, input) {
38
38
  if (!['capabilities', 'task-describe', 'message-route', 'message-accept', 'task-resume', 'task-checkpoint', 'flow-cancel', 'flow-abandon',
39
39
  'message-status', 'message-delivery-start', 'message-delivery-report', 'message-resolve', 'message-complete',
40
- 'handoff-prepare', 'handoff-release', 'handoff-claim', 'handoff-status', 'handoff-resume', 'handoff-execution-authority', 'mutation-snapshot-challenge', 'mutation-pass-issue',
40
+ 'handoff-prepare', 'handoff-release', 'handoff-claim', 'handoff-status', 'handoff-resume', 'handoff-execution-authority', 'mutation-snapshot-challenge', 'mutation-pass-issue', 'mutation-pass-settle',
41
+ 'member-observation-admit', 'member-observation-report', 'member-observation-status',
41
42
  'scope-runner-prepare', 'scope-runner-register', 'scope-runner-challenge', 'scope-runner-attest',
42
43
  'start', 'continue'].includes(operation)) throw new Error('Invalid entrorove operation');
43
44
  if (!input || typeof input !== 'object' || Array.isArray(input)) throw new Error('Input must be a JSON object');
@@ -1,5 +1,6 @@
1
1
  const ide = ['ide-code-mode.mjs', 'ide-command.mjs', 'ide-hook.mjs', 'ide-install.mjs', 'ide-session.mjs', 'break-glass.mjs', 'ide-results.mjs', 'ide-queue.mjs'];
2
2
  const discipline = ['local-discipline-actions.mjs', 'local-discipline-analysis.mjs', 'local-discipline-batch.mjs',
3
+ 'local-typescript-function-reference.mjs', 'local-scope-import-expressions.mjs',
3
4
  'local-discipline-contracts.mjs', 'local-discipline-contracts.d.mts', 'local-discipline-gate.mjs',
4
5
  'local-discipline-native.mjs', 'local-discipline-operations.mjs', 'local-discipline-repository.mjs',
5
6
  'local-discipline-snapshot.mjs', 'local-runner-discipline.mjs', 'local-integrity.d.mts'];
@@ -15,4 +16,6 @@ export const reuseDisciplineReleaseLabels = Object.fromEntries([
15
16
  ...cleanup.map(file => [file, { zh: '验收后快照自动清理', en: 'verified snapshot cleanup' }]),
16
17
  ...documentation.map(file => [file, { zh: 'IDE 执行与复用纪律文档', en: 'IDE execution and reuse discipline documentation' }]),
17
18
  ['reuse-discipline-release.mjs', { zh: '复用纪律版本追踪', en: 'reuse discipline release tracking' }],
19
+ ['local-typescript-function-reference.mjs', { zh: 'TypeScript 类型与 Vue 属性构造器引用分析', en: 'TypeScript type and Vue prop constructor references' }],
20
+ ['local-scope-import-expressions.mjs', { zh: '不可变有限动态导入与逐站点未核实诊断', en: 'immutable finite imports and precise unresolved import diagnostics' }],
18
21
  ]);
@@ -0,0 +1,44 @@
1
+ import { bootstrapCloudMutationAuthority } from './cloud-mutation-authority.mjs';
2
+ import { observationInput } from './workflow-observation-wire.mjs';
3
+
4
+ const safeId = value => typeof value === 'string' && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(value);
5
+ const safeRequest = value => typeof value === 'string' && /^[a-f0-9]{64}$/.test(value);
6
+ const messages = {
7
+ ENTROROVE_LOCAL_OBSERVATION_UNKNOWN: 'Original observation outcome is unknown; recover its original GET without repeating execution',
8
+ ENTROROVE_LOCAL_OBSERVATION_NOT_SENT: 'Observation was not transmitted; repair its local or discovery prerequisite and reuse the original input',
9
+ ENTROROVE_LOCAL_OBSERVATION_PREREQUISITE: 'Local observation requires cloud sandbox disabled and its original live execution lease',
10
+ ENTROROVE_SCOPE_RECEIPT_EXPIRED: 'Refresh the original scope evidence and reuse the original observation input',
11
+ ENTROROVE_SCOPE_AFTER_WRITE_REQUIRED: 'Observe the settled modifications in fresh scope evidence before local testing',
12
+ };
13
+ function blocked(error, input) {
14
+ const cause = error && typeof error === 'object' ? error : {};
15
+ const code = typeof cause.code === 'string' && /^ENTROROVE_[A-Z0-9_]{1,100}$/.test(cause.code)
16
+ ? cause.code : 'ENTROROVE_LOCAL_OBSERVATION';
17
+ const output = cause.output, requestId = safeRequest(cause.requestId) ? cause.requestId : undefined;
18
+ const recoverable = output?.status === 'blocked' && output.recoverable === true
19
+ && (output.observationPrerequisite?.effect === 'none' || ['ENTROROVE_SCOPE_RECEIPT_EXPIRED',
20
+ 'ENTROROVE_SCOPE_RUNNER_REQUIRED', 'ENTROROVE_SCOPE_SNAPSHOT_REQUIRED', 'ENTROROVE_SCOPE_AFTER_WRITE_REQUIRED'].includes(code));
21
+ const reason = ['sandbox-enabled', 'lease-expired', 'receipt-expired', 'after-write-observation-required'].includes(output?.reason)
22
+ ? output.reason : undefined;
23
+ return { schemaVersion: 'entrorove.local-observation-connection/1.0', status: 'blocked',
24
+ ...(safeId(input?.flowId) ? { flowId: input.flowId } : {}), independentValidation: 'pending', code,
25
+ message: messages[code] ?? 'Local observation could not continue; its original command and result remain preserved',
26
+ ...(recoverable ? { prerequisite: { status: 'blocked', code, recoverable: true, ...(reason ? { reason } : {}),
27
+ nextAction: { operation: 'workflow-observe-step', reuseOriginalInput: true,
28
+ ...(safeRequest(output.requestId) ? { resumeRequestId: output.requestId } : {}) } } } : {}),
29
+ ...(cause.outcomeUnknown === true && requestId ? { outcomeUnknown: true, requestId, repeatPost: false,
30
+ nextAction: { operation: 'workflow-observe-step', reuseOriginalInput: true, method: 'GET' } } : {}),
31
+ ...(cause.knownBeforeTransmission === true && requestId ? { requestId, knownBeforeTransmission: true } : {}) };
32
+ }
33
+ export async function runWorkflowObserveStep(repositoryRoot, input, dependencies) {
34
+ try {
35
+ observationInput(input);
36
+ await dependencies.install();
37
+ if (!await dependencies.agreementAccepted(dependencies.home)) return dependencies.agreementRequired(dependencies.home);
38
+ await bootstrapCloudMutationAuthority(dependencies);
39
+ const { connectWorkflowObservation } = await import('./workflow-observation-connection.mjs');
40
+ return await connectWorkflowObservation(repositoryRoot, input, dependencies);
41
+ } catch (error) {
42
+ return blocked(error, input);
43
+ }
44
+ }
@@ -0,0 +1,35 @@
1
+ import { canonical, sha256 } from './local-integrity.mjs';
2
+ import { withStateLock } from './local-state-lock.mjs';
3
+ import { trustedOrigin } from './remote-transport.mjs';
4
+ import { observationAdmission, observationFail } from './workflow-observation-wire.mjs';
5
+ import { observationLocation, readObservationState } from './workflow-observation-state.mjs';
6
+ import { runWorkflowObservation } from './workflow-observation-runner.mjs';
7
+ import { observationRemote, authorizeObservation } from './workflow-observation-remote.mjs';
8
+
9
+ async function connect(input, state, location, dependencies) {
10
+ const original = Object.fromEntries(['taskId', 'flowId', 'stepId', 'leaseId', 'generation', 'settlementId'].map(key => [key, input[key]]));
11
+ const admitted = state.admitted ?? await observationRemote('admitted', 'member-observation-admit', original, state, location, dependencies);
12
+ const admission = observationAdmission(admitted.admission, input, { allowExpired: Boolean(state.result) });
13
+ await authorizeObservation(admission, dependencies, !state.result);
14
+ const cached = Boolean(state.result), result = await runWorkflowObservation(input, admission, state, location,
15
+ { authorize: () => authorizeObservation(admission, dependencies, true) });
16
+ if (result.runner !== 'local' || result.receipt !== null || result.independentValidation !== 'pending'
17
+ || result.executionIsolation !== 'host-permissions' || result.externalEffects !== 'unverified'
18
+ || !['incomplete', 'failed'].includes(result.status) || result.admissionDigest !== sha256(canonical(admission))) {
19
+ observationFail('Local observation cannot replace independent validation or its original admitted result');
20
+ }
21
+ const reported = state.reported ?? await observationRemote('reported', 'member-observation-report', {
22
+ observationId: admission.observationId, admissionDigest: sha256(canonical(admission)), result,
23
+ }, state, location, dependencies);
24
+ if (reported.observationId !== admission.observationId || reported.observationStatus !== 'pending-independent'
25
+ || reported.resultDigest !== sha256(canonical(result)) || canonical(reported.result) !== canonical(result)) {
26
+ observationFail('Stored local observation differs from its actual original result');
27
+ }
28
+ return { ...result, taskId: input.taskId, flowId: input.flowId, stepId: input.stepId, cached, stored: true,
29
+ resultDigest: sha256(canonical(result)), grantsExecutionAuthority: false, grantsValidatorAuthority: false };
30
+ }
31
+ export async function connectWorkflowObservation(repositoryRoot, original, dependencies) {
32
+ const location = await observationLocation(repositoryRoot, original, dependencies.home, trustedOrigin(dependencies.apiOrigin()));
33
+ const input = { ...original, repositoryRoot: location.root, home: location.home };
34
+ return withStateLock(location.file, async () => connect(input, await readObservationState(location), location, dependencies));
35
+ }
@@ -0,0 +1,84 @@
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 { saveObservationState } from './workflow-observation-state.mjs';
7
+ import { observationFail } from './workflow-observation-wire.mjs';
8
+ import { readInvocations } from './local-invocations.mjs';
9
+
10
+ const unknown = requestId => Object.assign(new Error('Original local observation request outcome is unknown; recover its GET without repeating execution'),
11
+ { code: 'ENTROROVE_LOCAL_OBSERVATION_UNKNOWN', outcomeUnknown: true, requestId });
12
+ const notSent = requestId => Object.assign(new Error('Original local observation was not transmitted'),
13
+ { code: 'ENTROROVE_LOCAL_OBSERVATION_NOT_SENT', knownBeforeTransmission: true, requestId });
14
+ async function knownNotSent(pending, home) {
15
+ try {
16
+ const records = (await readInvocations(home)).filter(value => value.kind === 'remote'
17
+ && value.operation === pending.operation && value.requestId === pending.requestId);
18
+ return !records.length || records.at(-1).event === 'not-sent';
19
+ } catch (error) { return error?.code === 'ENOENT'; }
20
+ }
21
+ async function recover(pending, dependencies) {
22
+ const token = await dependencies.readCredential(dependencies.home), origin = dependencies.apiOrigin();
23
+ let response, result;
24
+ try {
25
+ response = await requestTransport(origin, `/api/skill/status/${pending.requestId}`, { headers: {
26
+ authorization: `Bearer ${token}`, ...ideClientHeaders() } });
27
+ result = parseTransportResponse(response, 'original local observation status');
28
+ if (!response.ok || result?.output?.requestId !== pending.requestId
29
+ || ['pending', 'running'].includes(result.output.status)) throw unknown(pending.requestId);
30
+ result.feedback ??= await queryAutomaticFeedback(pending.requestId, dependencies);
31
+ verifyAutomaticFeedback(result.feedback, pending.requestId, pending.requestId);
32
+ result.feedback = await acknowledgeAutomaticFeedback(result.feedback, origin, token, ideClientHeaders());
33
+ } catch { throw unknown(pending.requestId); }
34
+ return { response, result };
35
+ }
36
+ function prerequisite(output) {
37
+ return output?.status === 'blocked' && output.recoverable === true && (output.observationPrerequisite?.effect === 'none'
38
+ || ['ENTROROVE_SCOPE_RECEIPT_EXPIRED', 'ENTROROVE_SCOPE_RUNNER_REQUIRED', 'ENTROROVE_SCOPE_SNAPSHOT_REQUIRED',
39
+ 'ENTROROVE_SCOPE_AFTER_WRITE_REQUIRED'].includes(output.code));
40
+ }
41
+ export async function observationRemote(stage, operation, input, state, location, dependencies) {
42
+ const requestId = buildInvocation(operation, input).requestId;
43
+ let response, result;
44
+ if (state.pending) {
45
+ if (state.pending.stage !== stage || state.pending.operation !== operation || state.pending.requestId !== requestId
46
+ || canonical(state.pending.input) !== canonical(input)) observationFail('Original observation request must finish before another operation');
47
+ ({ response, result } = await recover(state.pending, dependencies));
48
+ } else {
49
+ state.pending = { stage, operation, input, requestId };
50
+ try { await saveObservationState(location, state); } catch { throw notSent(requestId); }
51
+ try { ({ response, result } = await invokeRemoteResult({ operation, input }, dependencies)); }
52
+ catch {
53
+ if (await knownNotSent(state.pending, dependencies.home)) {
54
+ delete state.pending;
55
+ try { await saveObservationState(location, state); } catch { throw notSent(requestId); }
56
+ throw notSent(requestId);
57
+ }
58
+ throw unknown(requestId);
59
+ }
60
+ }
61
+ if (!response.ok || !['reported', 'succeeded'].includes(result?.output?.status)) {
62
+ if (operation === 'member-observation-admit' && prerequisite(result?.output)) {
63
+ delete state.pending; await saveObservationState(location, state);
64
+ throw Object.assign(new Error(result.output.message ?? 'Original local observation prerequisite is unresolved'),
65
+ { code: result.output.code, output: result.output });
66
+ }
67
+ throw unknown(requestId);
68
+ }
69
+ state[stage] = result.output; delete state.pending; await saveObservationState(location, state);
70
+ return result.output;
71
+ }
72
+ export async function authorizeObservation(admission, dependencies, launching) {
73
+ const token = await dependencies.readCredential(dependencies.home);
74
+ const response = await requestTransport(dependencies.apiOrigin(), `/api/skill/flows/${admission.flowId}/status`, {
75
+ headers: { authorization: `Bearer ${token}`, ...ideClientHeaders() } });
76
+ const status = parseTransportResponse(response, 'original local observation account');
77
+ if (!response.ok || status?.schemaVersion !== 'entrorove.flow-status/1.0'
78
+ || status.flow?.flowId !== admission.flowId || status.flow.ownerId !== admission.ownerId
79
+ || launching && (status.flow.stepId !== admission.stepId || status.flow.status !== 'running'
80
+ || status.workflow?.phase !== 'execute' || status.workflow.terminalAt
81
+ || ['pending', 'declined'].includes(status.workflow.authorization))) {
82
+ observationFail('Current account cannot confirm its original local observation task and execution step');
83
+ }
84
+ }
@@ -0,0 +1,87 @@
1
+ import { promises as fs } from 'node:fs';
2
+ import { canonical, sha256 } from './local-integrity.mjs';
3
+ import { scopeRead, scopeTarget } from './local-scope-files.mjs';
4
+ import { regular } from './local-task-handoff-storage.mjs';
5
+ import { assertBudgetRunnerAllowed, withBudgetReadContext } from './local-budget-reads.mjs';
6
+ import { disciplineRepositoryObservation, disciplineRepositoryDifferences } from './local-discipline-repository.mjs';
7
+ import { runApprovedProcess } from './local-approved-process.mjs';
8
+ import { observationAdmission, observationFail } from './workflow-observation-wire.mjs';
9
+ import { saveObservationState } from './workflow-observation-state.mjs';
10
+
11
+ async function observeFile(input, expected) {
12
+ const before = await scopeTarget(input.repositoryRoot, expected.path, false, true);
13
+ const read = await scopeRead(input.repositoryRoot, expected.path, input);
14
+ const after = await scopeTarget(input.repositoryRoot, expected.path, false, true);
15
+ if (read.sha256 !== expected.sha256 || expected.mode !== undefined && expected.mode !== null && (after.stat.mode & 511) !== expected.mode
16
+ || before.stat.dev !== after.stat.dev || before.stat.ino !== after.stat.ino || before.stat.mode !== after.stat.mode) {
17
+ observationFail('Local observation source or dependency differs from its admitted bytes and permissions');
18
+ }
19
+ return { path: expected.path, sha256: read.sha256, mode: after.stat.mode & 511,
20
+ realPath: await fs.realpath(after.target), dev: after.stat.dev, ino: after.stat.ino };
21
+ }
22
+ async function files(input, manifest) {
23
+ const result = [];
24
+ for (const expected of manifest) result.push(await observeFile(input, expected));
25
+ return result;
26
+ }
27
+ async function executable(admission) {
28
+ const { bytes, stat } = await regular(admission.command.executable, 256 * 1024 * 1024);
29
+ if (sha256(bytes) !== admission.command.executableSha256) observationFail('Local observation executable differs from its frozen command hash');
30
+ return { mode: stat.mode, dev: stat.dev, ino: stat.ino };
31
+ }
32
+ const same = (before, after) => canonical(before) === canonical(after);
33
+ async function remains(action, expected) { try { return same(expected, await action()); } catch { return false; } }
34
+ function processMetadata(process) {
35
+ return Object.fromEntries(['status', 'started', 'startedAt', 'finishedAt', 'exitCode', 'signal', 'timedOut',
36
+ 'outputLimitExceeded', 'durationMs', 'stdoutSha256', 'stderrSha256', 'capturedBytes', 'droppedBytes'].map(key => [key, process[key]]));
37
+ }
38
+ async function execute(input, admission, state, location, options) {
39
+ if (state.run) observationFail('Original local observation already started or has an unknown outcome; a new process is forbidden');
40
+ observationAdmission(admission, input);
41
+ await assertBudgetRunnerAllowed(input);
42
+ const originalSources = await files(input, admission.sourceManifest), originalProtected = await files(input, admission.protectedFiles);
43
+ const originalExecutable = await executable(admission);
44
+ const before = (await disciplineRepositoryObservation(input, input.repositoryRoot)).comparison;
45
+ observationAdmission(admission, input);
46
+ state.run = { phase: 'running', pid: process.pid, startedAt: new Date().toISOString() };
47
+ await saveObservationState(location, state);
48
+ let processResult;
49
+ try {
50
+ await assertBudgetRunnerAllowed(input);
51
+ if (!same(originalSources, await files(input, admission.sourceManifest))
52
+ || !same(originalProtected, await files(input, admission.protectedFiles))
53
+ || !same(originalExecutable, await executable(admission))) observationFail('Local observation inputs changed immediately before execution');
54
+ observationAdmission(admission, input);
55
+ if (options.authorize) await options.authorize();
56
+ observationAdmission(admission, input);
57
+ processResult = await runApprovedProcess({ root: input.repositoryRoot, policy: admission.command,
58
+ objectPlan: true, startDeadlineAt: admission.expiresAt });
59
+ } catch (error) {
60
+ if (!error?.execution?.process) {
61
+ state.run.phase = 'aborted'; await saveObservationState(location, state);
62
+ observationFail('Local observation stopped before a completed process; recover the original observation without rerunning');
63
+ }
64
+ processResult = error.execution.process;
65
+ }
66
+ let after = before, budgetAllowed = true;
67
+ try { await assertBudgetRunnerAllowed(input); after = (await disciplineRepositoryObservation(input, input.repositoryRoot)).comparison; }
68
+ catch { budgetAllowed = false; }
69
+ const checks = { sourceManifestUnchanged: budgetAllowed && await remains(() => files(input, admission.sourceManifest), originalSources),
70
+ protectedFilesUnchanged: budgetAllowed && await remains(() => files(input, admission.protectedFiles), originalProtected),
71
+ repositoryUnchanged: budgetAllowed && disciplineRepositoryDifferences(before, after).length === 0
72
+ && await remains(() => executable(admission), originalExecutable) };
73
+ state.result = { schemaVersion: 'entrorove.local-observation-result/1.0', observationId: admission.observationId,
74
+ admissionDigest: sha256(canonical(admission)), status: processResult.status === 'succeeded' && Object.values(checks).every(Boolean) ? 'incomplete' : 'failed',
75
+ independentValidation: 'pending', runner: 'local', receipt: null,
76
+ executionIsolation: 'host-permissions', externalEffects: 'unverified', process: processMetadata(processResult),
77
+ sourceManifestDigest: sha256(canonical(admission.sourceManifest)), checks,
78
+ beforeRepositoryDigest: sha256(canonical(before)), afterRepositoryDigest: sha256(canonical(after)) };
79
+ state.resultDigest = sha256(canonical(state.result)); state.run.phase = 'finished';
80
+ await saveObservationState(location, state);
81
+ return state.result;
82
+ }
83
+ export async function runWorkflowObservation(input, admission, state, location, options = {}) {
84
+ observationAdmission(admission, input, { allowExpired: Boolean(state.result) });
85
+ if (state.result) return state.result;
86
+ return withBudgetReadContext(input, () => execute(input, admission, state, location, options));
87
+ }
@@ -0,0 +1,36 @@
1
+ import path from 'node:path';
2
+ import { canonical, sha256 } from './local-integrity.mjs';
3
+ import { mutationRoot14, mutationHome14, mutationStateRoot14, privateMutationDirectory14,
4
+ readMutationJson14, atomicMutationJson14 } from './local-mutation-files.mjs';
5
+ import { observationExact, observationFail } from './workflow-observation-wire.mjs';
6
+
7
+ export async function observationLocation(repositoryRoot, input, home, apiOrigin) {
8
+ const root = await mutationRoot14(repositoryRoot), actualHome = await mutationHome14(home);
9
+ const relative = path.relative(root, actualHome);
10
+ if (!relative || relative !== '..' && !relative.startsWith(`..${path.sep}`) && !path.isAbsolute(relative)) {
11
+ observationFail('Local observation state must be outside the observed repository');
12
+ }
13
+ const identity = { ...input, repositoryRoot: root, home: actualHome, apiOrigin };
14
+ const stateRoot = await mutationStateRoot14({ home: actualHome });
15
+ const directory = path.join(stateRoot, 'local-observations', sha256(root).slice(0, 32), input.flowId, sha256(canonical(identity)));
16
+ await privateMutationDirectory14(directory, { privateFrom: stateRoot });
17
+ return { root, home: actualHome, identity, stateRoot, file: path.join(directory, 'journal.json') };
18
+ }
19
+ export async function readObservationState(location) {
20
+ let state;
21
+ try { state = await readMutationJson14(location.file); }
22
+ catch (error) { if (error.code !== 'ENOENT') throw error; }
23
+ if (!state) return { schemaVersion: 'entrorove.local-observation-state/1.0', identity: location.identity };
24
+ if (state.schemaVersion !== 'entrorove.local-observation-state/1.0' || canonical(state.identity) !== canonical(location.identity)) {
25
+ observationFail('Local observation journal lost its original repository, home, task or settlement');
26
+ }
27
+ if (state.result && state.resultDigest !== sha256(canonical(state.result))) observationFail('Local observation stored result integrity changed');
28
+ if (state.run) {
29
+ observationExact(state.run, ['phase', 'pid', 'startedAt']);
30
+ if (!['running', 'finished', 'aborted'].includes(state.run.phase) || !Number.isSafeInteger(state.run.pid)
31
+ || !Number.isFinite(Date.parse(state.run.startedAt))) observationFail('Local observation running state is invalid');
32
+ }
33
+ return state;
34
+ }
35
+ export const saveObservationState = (location, state) => atomicMutationJson14(location.file, state,
36
+ { privateFrom: location.stateRoot, replace: true });