@entrorove/skill 0.1.78 → 0.1.81
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 -2
- package/CHANGELOG.md +14 -0
- package/SKILL.md +1 -1
- package/cli.mjs +2 -2
- package/local-approved-process.mjs +5 -1
- package/local-cli.mjs +40 -1
- package/manifest.json +1 -1
- package/package.json +3 -2
- package/release-source-groups.mjs +2 -0
- package/release-state.json +14 -12
- package/releases.json +18 -0
- package/scope-runner-client.mjs +5 -1
- package/workflow-observation-client.mjs +2 -1
- package/workflow-observation-connection.mjs +4 -1
- package/workflow-observation-interruption.mjs +12 -0
- package/workflow-observation-recovery.mjs +42 -0
- package/workflow-observation-runner.mjs +13 -6
package/CAPABILITY-MAP.md
CHANGED
|
@@ -44,7 +44,7 @@ New tasks declare their concrete `task.authorization` boundary at entrance and o
|
|
|
44
44
|
| 网页与手机通知 | 登录后的任务通知按钮 | 同一加密 Web Push 协议,账号与设备隔离;真实任务事务队列、持久重试、失效注销与到期清理;手机可见投递仍需设备本人授权与验收 |
|
|
45
45
|
| 失败后接续 | `scope-connect` 返回 `nextInput`;`feedback <requestId> [generation]` | 范围门禁使用同一排序路径集;新执行保存新一代回执,原失败回执不可改,默认只读最新一代 |
|
|
46
46
|
|
|
47
|
-
本地公开 schema 已增加到 **
|
|
47
|
+
本地公开 schema 已增加到 **115 项**(原 100 项加 `peer-status`,当前增量的 `discipline-check`、`discipline-review`、`flow-cancel`、`flow-abandon`、`guarded-delete`、`guarded-move`、`mutation-delegate-prepare`、`mutation-consumption-attest`,以及界面设计门禁的 `design-browser-info`、`design-flow`、`design-research`、`design-propose`、`design-status`、`design-verify`)。Aimlock 运行时由 7.0.44 更新为 **7.0.45**,公开操作由 20 项增加到 24 项;其余七域的运行时版本保持原值。下方历史表保留原对账日期与当时验收边界,不表示当前仍缺上述入口。发布件与生产部署需独立核验,不能从仓库测试推断。
|
|
48
48
|
|
|
49
49
|
## 2026-10-12 基线:八域 IDE 调用链
|
|
50
50
|
|
|
@@ -107,7 +107,7 @@ Entrorove 只治理通过技能入口执行的动作:路径、通行证、快
|
|
|
107
107
|
|
|
108
108
|
`scope-context <original repositoryRoot>` 处理首次范围事实尚未建立时遗漏的真实构建上下文。`review` 保存完整旧/新映射和实际配置、构建来源摘要,经原账号明确回答后,`apply` 用原 S、服务挑战、真实快照和导入图追加上下文权威记录;再以全部原路径继续 `scope-connect`。保留原 binding、签名器及失败历史,不授予写入或完成权限,已有范围事实或 gate 后不能使用此入口。远端 `scope-runner-context-review/status/challenge/apply` 均以实时发现为准。
|
|
109
109
|
|
|
110
|
-
当前增量操作(不改写上述历史分母)为:`peer-status`、`discipline-check`、`discipline-review`、`flow-cancel`、`flow-abandon`、`guarded-delete`、`guarded-move`、`mutation-delegate-prepare`、`mutation-consumption-attest`。它们计入当前
|
|
110
|
+
当前增量操作(不改写上述历史分母)为:`peer-status`、`discipline-check`、`discipline-review`、`flow-cancel`、`flow-abandon`、`guarded-delete`、`guarded-move`、`mutation-delegate-prepare`、`mutation-consumption-attest`、`design-browser-info`、`design-flow`、`design-research`、`design-propose`、`design-status`、`design-verify`。它们计入当前 115 项公开 schema。
|
|
111
111
|
|
|
112
112
|
| 分区 | 精确操作名 | 证据位置 |
|
|
113
113
|
| --- | --- | --- |
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.81 - 2026-10-23
|
|
4
|
+
|
|
5
|
+
仓库不再保留自动化测试与调试脚本,发布内容与安装包只包含运行所需文件。八个核心技能的实现与权限边界保持不变。
|
|
6
|
+
|
|
7
|
+
## 0.1.80 — 2026-10-22
|
|
8
|
+
|
|
9
|
+
- 更新了技能运行和受管安装、能力覆盖映射、本地执行命令。
|
|
10
|
+
- Updated skill runtime and managed installation, capability coverage map, local execution command.
|
|
11
|
+
|
|
12
|
+
## 0.1.79 — 2026-10-22
|
|
13
|
+
|
|
14
|
+
- 修复干净安装后首次范围连接的服务公钥发现与私有绑定;补齐原任务本地观察的中断恢复并保留失败、未知和真实回执。配套服务修复范围修订路径排序,避免数据库语言环境误拒合法签名。八个核心技能的原实现与权限边界保持。
|
|
15
|
+
- Fix authenticated public authority discovery and private pinning on the first scope connection after a clean install. Complete original-task local observation recovery while preserving failures, unknown outcomes and real receipts. The companion service fixes canonical scope revision path ordering across database locales. Preserve the eight original skill implementations and authority boundaries.
|
|
16
|
+
|
|
3
17
|
## 0.1.78 — 2026-10-21
|
|
4
18
|
|
|
5
19
|
- 完整交付原八技能的一次入口授权、范围内衔接与有界恢复;修复已实际取消的弹窗先于点击回执关闭时的原窗口接续,不重发点击,原父窗口、精确路由、安全签名、快照及回执保护保持。
|
package/SKILL.md
CHANGED
|
@@ -5,7 +5,7 @@ description: Route a task selected for Entrorove among its eight skills, approve
|
|
|
5
5
|
|
|
6
6
|
# entrorove · 熵巡
|
|
7
7
|
|
|
8
|
-
Version: 0.1.
|
|
8
|
+
Version: 0.1.81.
|
|
9
9
|
|
|
10
10
|
Entrorove applies only to the task for which it is selected; reading these instructions, discovering capabilities or installing the package never selects or governs another task. Hooks are optional. Reading this document or calling an entry once does not execute the task. On every later turn, including after compaction, continue the original task and its required next operation before dependent work. Keep the original goal, scope, account, flow, cloud task and failure records. Never describe planning, a reported step or model output as verified delivery.
|
|
11
11
|
|
package/cli.mjs
CHANGED
|
@@ -8,7 +8,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
8
8
|
import { compareVersions } from './version.mjs';
|
|
9
9
|
import { installPackageIdentity } from './install-identity.mjs';
|
|
10
10
|
import { credentialPath, readCredential, writeCredential } from './local-credential.mjs';
|
|
11
|
-
import { runLocal } from './local-cli.mjs';
|
|
11
|
+
import { runLocal, optionalStdinJson } from './local-cli.mjs';
|
|
12
12
|
import { runNative } from './native-client.mjs';
|
|
13
13
|
import { configureNativeNotifications, notificationSettings, sendNativeNotification } from './native-notification.mjs';
|
|
14
14
|
import { runTaskMessageCli } from './task-message-cli.mjs';
|
|
@@ -461,7 +461,7 @@ async function main() {
|
|
|
461
461
|
} else if (command === 'invoke' && args.length === 0) {
|
|
462
462
|
await invoke(await stdinJson());
|
|
463
463
|
} else if (command === 'native' && args.length === 2) {
|
|
464
|
-
await runNative(args[0], args[1], await stdinJson(), remoteDependencies());
|
|
464
|
+
await runNative(args[0], args[1], ['capabilities', 'help'].includes(args[1]) ? await optionalStdinJson() : await stdinJson(), remoteDependencies());
|
|
465
465
|
} else if (command === 'notifications' && args.length === 1) {
|
|
466
466
|
const result = args[0] === 'configure' ? await configureNativeNotifications(await stdinJson())
|
|
467
467
|
: args[0] === 'status' ? await notificationSettings()
|
|
@@ -25,7 +25,11 @@ function supervisionError(code, message, effects = 'unknown') {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
export async function runApprovedProcess(authority) {
|
|
28
|
-
const started = performance.now()
|
|
28
|
+
const started = performance.now();
|
|
29
|
+
let input;
|
|
30
|
+
try { input = launchInput(authority); }
|
|
31
|
+
catch (error) { throw Object.assign(error, { execution: { schemaVersion: RUNNER_SCHEMA, status: 'failed', evidence: [],
|
|
32
|
+
effects: 'none', prelaunchVerified: true } }); }
|
|
29
33
|
return new Promise((resolve, reject) => {
|
|
30
34
|
let finished = false;
|
|
31
35
|
const supervisor = fork(SUPERVISOR, [], { execPath: process.execPath, execArgv: [], env: {}, detached: true,
|
package/local-cli.mjs
CHANGED
|
@@ -44,6 +44,45 @@ async function stdinJson() {
|
|
|
44
44
|
return value;
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
// Discovery takes an optional input object. A host that keeps stdin open
|
|
48
|
+
// without writing must not block the skill, so wait only briefly for data.
|
|
49
|
+
export async function optionalStdinJson(idleMs = 200) {
|
|
50
|
+
if (process.stdin.isTTY) return {};
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
let raw = '';
|
|
53
|
+
let settled = false;
|
|
54
|
+
let timer;
|
|
55
|
+
const cleanup = () => {
|
|
56
|
+
if (timer) clearTimeout(timer);
|
|
57
|
+
process.stdin.off('data', onData);
|
|
58
|
+
process.stdin.off('end', onEnd);
|
|
59
|
+
process.stdin.off('error', onError);
|
|
60
|
+
process.stdin.pause();
|
|
61
|
+
};
|
|
62
|
+
const finish = (error) => {
|
|
63
|
+
if (settled) return;
|
|
64
|
+
settled = true;
|
|
65
|
+
cleanup();
|
|
66
|
+
if (error) return reject(error);
|
|
67
|
+
if (!raw.trim()) return resolve({});
|
|
68
|
+
let value;
|
|
69
|
+
try { value = JSON.parse(raw); } catch { return reject(new Error('Local input must be valid JSON')); }
|
|
70
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
71
|
+
return reject(new Error('local input must be a JSON object'));
|
|
72
|
+
}
|
|
73
|
+
resolve(value);
|
|
74
|
+
};
|
|
75
|
+
const onData = chunk => { raw += chunk; };
|
|
76
|
+
const onEnd = () => finish();
|
|
77
|
+
const onError = error => finish(error);
|
|
78
|
+
process.stdin.on('data', onData);
|
|
79
|
+
process.stdin.once('end', onEnd);
|
|
80
|
+
process.stdin.once('error', onError);
|
|
81
|
+
timer = setTimeout(() => finish(), idleMs);
|
|
82
|
+
process.stdin.resume();
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
|
|
47
86
|
const operations = {
|
|
48
87
|
'mutation-consumption-attest': attestMutationConsumption14,
|
|
49
88
|
'mutation-delegate-prepare': preparePreservedMutationSigner,
|
|
@@ -102,7 +141,7 @@ export async function runLocal(args = [], dependencies) {
|
|
|
102
141
|
try {
|
|
103
142
|
const operation = args[0];
|
|
104
143
|
if (operation === 'capabilities' || operation === 'help') {
|
|
105
|
-
validateLocalInput(operation,
|
|
144
|
+
validateLocalInput(operation, await optionalStdinJson());
|
|
106
145
|
process.stdout.write(`${JSON.stringify(capabilitiesFor(args[1]))}\n`); return;
|
|
107
146
|
}
|
|
108
147
|
const handler = operations[operation];
|
package/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@entrorove/skill",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.81",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"entrorove": "cli.mjs"
|
|
@@ -290,6 +290,8 @@
|
|
|
290
290
|
"workflow-observation-connection.mjs",
|
|
291
291
|
"workflow-observation-remote.mjs",
|
|
292
292
|
"workflow-observation-runner.mjs",
|
|
293
|
+
"workflow-observation-recovery.mjs",
|
|
294
|
+
"workflow-observation-interruption.mjs",
|
|
293
295
|
"workflow-observation-state.mjs",
|
|
294
296
|
"workflow-observation-wire.mjs",
|
|
295
297
|
"member-producer-repair-authority.mjs",
|
|
@@ -345,7 +347,6 @@
|
|
|
345
347
|
"scope-runner-journal.mjs"
|
|
346
348
|
],
|
|
347
349
|
"scripts": {
|
|
348
|
-
"test": "node test/run.mjs",
|
|
349
350
|
"prepublishOnly": "node release.mjs",
|
|
350
351
|
"prepare:archguard": "node archguard-runtime-build.mjs",
|
|
351
352
|
"check:archguard": "node archguard-runtime-build.mjs --check",
|
|
@@ -34,6 +34,8 @@ export const memberContinuationSourceFiles = Object.freeze([
|
|
|
34
34
|
'workflow-observation-connection.mjs',
|
|
35
35
|
'workflow-observation-remote.mjs',
|
|
36
36
|
'workflow-observation-runner.mjs',
|
|
37
|
+
'workflow-observation-recovery.mjs',
|
|
38
|
+
'workflow-observation-interruption.mjs',
|
|
37
39
|
'workflow-observation-state.mjs',
|
|
38
40
|
'workflow-observation-wire.mjs',
|
|
39
41
|
])
|
package/release-state.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "entrorove.release-state/1.0",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"digest": "
|
|
3
|
+
"version": "0.1.81",
|
|
4
|
+
"digest": "02c6175ebaa09bad61e9b3128bf3408561390c6d307feb31a7dd6f737f5903fe",
|
|
5
5
|
"files": {
|
|
6
6
|
"local-recovery-budget.mjs": "be3af07db8e4cc96782edb130e827039c7a99bbe8275a92f0f741533716017f3",
|
|
7
7
|
"remote-capability-cache.mjs": "9c22067e1a21eb2a209747a8ab2f27c0496b14a22a7e0f5654840e2035148df0",
|
|
8
8
|
"scope-write-observation.mjs": "d832adce75cbe005d683bc6bd2571220e13ad7b0651235688b02993e8f2c3796",
|
|
9
9
|
"scope-write-observation.d.mts": "52fb0b805494d83673fb4d0ffb5f6b1bc39854b400a8799fe2446681696ed8b3",
|
|
10
|
-
"release-source-groups.mjs": "
|
|
10
|
+
"release-source-groups.mjs": "84532d6de7c114fd26b56037d5df4fb246571b8bb74148360eb46f3d094803c6",
|
|
11
11
|
"local-scope-build-read.mjs": "361d4b461cfa2c77b4ec22bc59a0a1c78fed2cfb0ea2e05a8da5c2551ecd88ac",
|
|
12
12
|
"local-scope-build-io.mjs": "8af69722738fa094780f9a2dfcddaf12993fc3b936a75c56c4b0d4f90cb20fd1",
|
|
13
13
|
"local-scope-build-facts.mjs": "8b0bd19347d06d1cb66d8cd2d6784103af9d00ea691d7f4acea523d994b874fb",
|
|
@@ -44,14 +44,16 @@
|
|
|
44
44
|
"local-finder-store.mjs": "227191c52174386ace6391e072b78a6e4cc658a6d9dd37036ffd7e97bbf4336a",
|
|
45
45
|
"local-finder-plist.mjs": "c83ddab2375a54d612d395a5518db8ae05212437d82bf3f8b76930a8859c8481",
|
|
46
46
|
"connected-cli.mjs": "29ab700f6a308adad5f3984bf9dd2734755a29fbd0e963e630222565846b5942",
|
|
47
|
-
"local-approved-process.mjs": "
|
|
47
|
+
"local-approved-process.mjs": "f37266b4fc14af358b2781b05034c7e733fcb049a72300250c8dd0f6edb0cad8",
|
|
48
48
|
"local-approved-supervisor.mjs": "87142a4c13d27c8265cc1fd7fc9088988da9bbb02134164e1a7c5417da926ac7",
|
|
49
49
|
"local-mutation-consumption.mjs": "1b033655f817ec576410b7f91f1640b8651f3cff0668154fb8e6e14e7b31d8f4",
|
|
50
50
|
"workflow-local-acceptance.mjs": "743ae19c1edff473af2596c7356ddff3892ff9acfb3bcaa660b662eacba463a8",
|
|
51
|
-
"workflow-observation-client.mjs": "
|
|
52
|
-
"workflow-observation-connection.mjs": "
|
|
51
|
+
"workflow-observation-client.mjs": "6b356fa54de1a53fcac0abb249fafc4cb52fa331e8098537719ed6418f5e51f5",
|
|
52
|
+
"workflow-observation-connection.mjs": "eefda0cb4dd34d3d6ac3ba154887edeb6c62492187fc2bbe70284c0c7e98c65e",
|
|
53
53
|
"workflow-observation-remote.mjs": "9d4120b94892e58b815f7dfcc1773623749fd5d75b0bb0f4a7548b60412fd8e6",
|
|
54
|
-
"workflow-observation-runner.mjs": "
|
|
54
|
+
"workflow-observation-runner.mjs": "2fec8041fd111d6cc05f82cb106e2e1e21aa59cb67bd3e9bfcb96fe97aee12e3",
|
|
55
|
+
"workflow-observation-recovery.mjs": "a0cdbc065b5e3e90d6ac3f6a9546e9e142d02ec8e646f1659a860809338baf19",
|
|
56
|
+
"workflow-observation-interruption.mjs": "08339e313a0ac0e706bfe6fbfa6b2235e9c41e8b0f55a1aa6bf64af07a9b228b",
|
|
55
57
|
"workflow-observation-state.mjs": "a525046df9b3de75b10d2bf35c2b6d7719f12a647e4aee1f1e85dbdbfb167321",
|
|
56
58
|
"workflow-observation-wire.mjs": "df0d5e4f8fde0be8bf06c6c4590cd158b4da05ebe6ef3169d2366db706f3327f",
|
|
57
59
|
"local-preserved-mutation-protection.mjs": "289bf58933818ff13b217d0d75afd0b81cc59bc09b4ea88f50a2ab900e9cf1c2",
|
|
@@ -166,20 +168,20 @@
|
|
|
166
168
|
"local-autocoord17-waits.mjs": "2b0a713987822548a94e1ed3a9a891532db45383797dfc5d5bc8d1e35593cf25",
|
|
167
169
|
"local-validator-isolation17.mjs": "48e94604e28b8fddd567dfb35ff60b73fd094a5803bd49f076388b7f310f92aa",
|
|
168
170
|
"local-calctool-composition17.mjs": "ac89fcb41ab0d0d9b47c1b5696945281b0894eb064820775e36a011c76314e6a",
|
|
169
|
-
"cli.mjs": "
|
|
171
|
+
"cli.mjs": "894f77e3db0cd2ec856df1759619900430817d24564f13d1ad3ee470d7c7e9d1",
|
|
170
172
|
"ide-selection.mjs": "e11e2b363c06444f1dcb4cdab1eaa0eb748a379b84354e0e71fd9c2dc79a4815",
|
|
171
173
|
"ide-exit.mjs": "39d60a15b1517d402c208d22a17033976e43733be8a10dc6da386837c59b37b2",
|
|
172
174
|
"install-cleanup.mjs": "8a8e1a7dfe37427f86cd4d6e317890d0829894a9949d4216674a716b36edbc54",
|
|
173
175
|
"review-client.mjs": "3491eef68ed533174b31db3c53febb6519b8f088f71a9964644714a9a4c03c77",
|
|
174
176
|
"version.mjs": "85284d4cd5e3314b449e6ae124243f96397bcc274817b5983a79cfdd903d46fd",
|
|
175
177
|
"SKILL.md": "5f68fe2742dfd64feeff7e5071719c1de5d09dd7f33f44cb742499f6dab3d3c9",
|
|
176
|
-
"CAPABILITY-MAP.md": "
|
|
178
|
+
"CAPABILITY-MAP.md": "57805ba6a4b4fc79ffadb3bd1436999f82c295feac7bdc230bdc123f67662546",
|
|
177
179
|
"AGREEMENT.md": "f93a68e92c457200dd024610e65f74e478b8f60860f951da818b70561f1b9bf8",
|
|
178
180
|
"DELIVERY-BOUNDARIES.md": "cb23ce71b2197085c8441ba7c5b6c05fb21f2a954bf66b4d60cfef8b15895b8b",
|
|
179
|
-
"package.json": "
|
|
181
|
+
"package.json": "84839cc341dcd8073bd870462ee9243c66c1cf8dacc78198f5e6b54bf39226c5",
|
|
180
182
|
"manifest.json": "ab06e307795bc9da5add926752b6c4dbdaf18625090261a035aa356a679c504f",
|
|
181
183
|
"release.mjs": "2070c03cbaaa64387452d07687c6ce8d6c4ff6cfeb2b10094082621e10e8588f",
|
|
182
|
-
"local-cli.mjs": "
|
|
184
|
+
"local-cli.mjs": "6c12beed3c43a484e1afd266055179dec17d56a9c04846d67a279445d50da095",
|
|
183
185
|
"local-state-lock.mjs": "1dbf64264642a0851faf043e07ee9f66d2ad0508e9f799b0626246e42fae893e",
|
|
184
186
|
"local-execution.mjs": "721ed7d29bbe4ce6d088909cd84ffc440978c3c9eb0946c49a4281ee685fe3aa",
|
|
185
187
|
"local-integrity.mjs": "e6d6eace80c610f3c7299d4f8644b0dc023aa9e3d8d64b26535ea7fbced248f1",
|
|
@@ -260,7 +262,7 @@
|
|
|
260
262
|
"local-source-execution.mjs": "88f6ce1ea50d0a7b92e0cb47d535f8140491c52d9c6c0dfddf91ea90397a36f5",
|
|
261
263
|
"fs-request-trace.mjs": "972eacbe21537bc102047127327449a6a4b0f0c65d75e3472370de91dedf4d2f",
|
|
262
264
|
"cloud-task-client.mjs": "ab3e0296363b6af10eaa38a09dd43b4ae6e5704d699c7a5032fee1b7817fa0dc",
|
|
263
|
-
"scope-runner-client.mjs": "
|
|
265
|
+
"scope-runner-client.mjs": "b8bf4aff4d45c2a7e92afd43e9ba6062d220dd42f2009bd91a18a516a2a1bc28",
|
|
264
266
|
"scope-amendment-client.mjs": "04109dd0b11ffe02b33ba2faeaadef0a8fb0026604835ec2f5c756085a8c1ea8",
|
|
265
267
|
"scope-amendment-state.mjs": "85240255f20650403e7fab084d5baace6710b5d3ecb1541b64ec3e9657fc71a9",
|
|
266
268
|
"scope-amendment-wire.mjs": "3c4823e23bbdf330616bb675f07f9fcad7423266bd50b92e1134d226060e9b83",
|
package/releases.json
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.1.81",
|
|
4
|
+
"date": "2026-10-23",
|
|
5
|
+
"zh": "仓库不再保留自动化测试与调试脚本,发布内容与安装包只包含运行所需文件。八个核心技能的实现与权限边界保持不变。",
|
|
6
|
+
"en": "The repository no longer carries automated tests or debugging scripts; the published tarball contains runtime files only. The eight core skill implementations and their authority boundaries are unchanged."
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"version": "0.1.80",
|
|
10
|
+
"date": "2026-10-22",
|
|
11
|
+
"zh": "更新了技能运行和受管安装、能力覆盖映射、本地执行命令。",
|
|
12
|
+
"en": "Updated skill runtime and managed installation, capability coverage map, local execution command."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"version": "0.1.79",
|
|
16
|
+
"date": "2026-10-22",
|
|
17
|
+
"zh": "修复干净安装后首次范围连接的服务公钥发现与私有绑定;补齐原任务本地观察的中断恢复并保留失败、未知和真实回执。配套服务修复范围修订路径排序,避免数据库语言环境误拒合法签名。八个核心技能的原实现与权限边界保持。",
|
|
18
|
+
"en": "Fix authenticated public authority discovery and private pinning on the first scope connection after a clean install. Complete original-task local observation recovery while preserving failures, unknown outcomes and real receipts. The companion service fixes canonical scope revision path ordering across database locales. Preserve the eight original skill implementations and authority boundaries."
|
|
19
|
+
},
|
|
2
20
|
{
|
|
3
21
|
"version": "0.1.78",
|
|
4
22
|
"date": "2026-10-21",
|
package/scope-runner-client.mjs
CHANGED
|
@@ -13,6 +13,7 @@ import { scopeRunnerJournal, saveScopeRunnerJournal, renewScopeRunnerChallenge,
|
|
|
13
13
|
import { saveLocalScopeEvidence, ensureScopeEvidence } from './scope-evidence-remote.mjs';
|
|
14
14
|
import { boundScopeContexts } from './scope-context-state.mjs';
|
|
15
15
|
import { mutationFile14 } from './local-mutation-files.mjs';
|
|
16
|
+
import { bootstrapCloudMutationAuthority } from './cloud-mutation-authority.mjs';
|
|
16
17
|
|
|
17
18
|
async function privateDirectory(directory) {
|
|
18
19
|
await fs.mkdir(directory, { recursive: true, mode: 0o700 });
|
|
@@ -180,7 +181,10 @@ export async function connectScopeRunner(repositoryRoot, input, dependencies) {
|
|
|
180
181
|
export async function runScopeConnect(repositoryRoot, input, dependencies) {
|
|
181
182
|
await dependencies.install();
|
|
182
183
|
if (!await dependencies.agreementAccepted(dependencies.home)) return dependencies.agreementRequired(dependencies.home);
|
|
183
|
-
try {
|
|
184
|
+
try {
|
|
185
|
+
await bootstrapCloudMutationAuthority(dependencies);
|
|
186
|
+
return await connectScopeRunner(repositoryRoot, input, dependencies);
|
|
187
|
+
}
|
|
184
188
|
catch (error) {
|
|
185
189
|
if (!error.code?.startsWith('ENTROROVE_')) throw error;
|
|
186
190
|
return { schemaVersion: 'entrorove.scope-connection/1.0', status: 'blocked', flowId: input?.flowId,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { prerequisiteFields } from './service-prerequisite.mjs';
|
|
2
2
|
import { bootstrapCloudMutationAuthority } from './cloud-mutation-authority.mjs';
|
|
3
3
|
import { observationInput } from './workflow-observation-wire.mjs';
|
|
4
|
+
import { recoveryFailureFields } from './local-recovery-budget.mjs';
|
|
4
5
|
|
|
5
6
|
const safeId = value => typeof value === 'string' && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(value);
|
|
6
7
|
const safeRequest = value => typeof value === 'string' && /^[a-f0-9]{64}$/.test(value);
|
|
@@ -32,7 +33,7 @@ function blocked(error, input) {
|
|
|
32
33
|
&& Number.isSafeInteger(cause.rejection.generation) && cause.rejection.generation > 0
|
|
33
34
|
&& ['member-observation-admit', 'member-observation-report'].includes(cause.rejection.operation);
|
|
34
35
|
return { schemaVersion: 'entrorove.local-observation-connection/1.0', status: 'blocked',
|
|
35
|
-
...prerequisiteFields(cause),
|
|
36
|
+
...prerequisiteFields(cause), ...recoveryFailureFields(cause),
|
|
36
37
|
...(safeId(input?.flowId) ? { flowId: input.flowId } : {}), independentValidation: 'pending', code,
|
|
37
38
|
message: messages[code] ?? 'Local observation could not continue; its original command and result remain preserved',
|
|
38
39
|
...(recoverable ? { prerequisite: { status: 'blocked', code, recoverable: true, ...(reason ? { reason } : {}),
|
|
@@ -7,13 +7,16 @@ import { runWorkflowObservation } from './workflow-observation-runner.mjs';
|
|
|
7
7
|
import { observationRemote, authorizeObservation } from './workflow-observation-remote.mjs';
|
|
8
8
|
import { verifyWorkflowLocalAcceptance } from './workflow-local-acceptance.mjs';
|
|
9
9
|
import { buildInvocation } from './remote-client.mjs';
|
|
10
|
+
import { recoverInterruptedObservation } from './workflow-observation-recovery.mjs';
|
|
10
11
|
|
|
11
12
|
async function connect(input, state, location, dependencies) {
|
|
12
13
|
const fields = ['taskId', 'flowId', 'stepId', 'leaseId', 'generation', ...(Object.hasOwn(input, 'settlementId') ? ['settlementId'] : []),
|
|
13
14
|
...(Object.hasOwn(input, 'dependencyRepairDigest') ? ['dependencyRepairDigest'] : [])];
|
|
14
15
|
const original = Object.fromEntries(fields.map(key => [key, input[key]]));
|
|
15
16
|
const admitted = state.admitted ?? await observationRemote('admitted', 'member-observation-admit', original, state, location, dependencies);
|
|
16
|
-
const
|
|
17
|
+
const recovering = !state.result && (Boolean(state.run) || Date.parse(admitted.admission?.expiresAt) <= Date.now());
|
|
18
|
+
const admission = observationAdmission(admitted.admission, input, { allowExpired: Boolean(state.result) || recovering });
|
|
19
|
+
if (recovering) return recoverInterruptedObservation(original, admission, state, location, dependencies);
|
|
17
20
|
await authorizeObservation(admission, dependencies, !state.result);
|
|
18
21
|
const cached = Boolean(state.result), result = await runWorkflowObservation(input, admission, state, location,
|
|
19
22
|
{ authorize: () => authorizeObservation(admission, dependencies, true) });
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { sha256 } from './local-integrity.mjs';
|
|
2
|
+
|
|
3
|
+
// This evidence is created only inside the live launch boundary. An old journal
|
|
4
|
+
// saying "aborted", or a missing PID, cannot be promoted into this proof.
|
|
5
|
+
export function notStartedProcess(error, beforeLaunch) {
|
|
6
|
+
if (!beforeLaunch && (error?.execution?.effects !== 'none' || error.execution.prelaunchVerified !== true)) return null;
|
|
7
|
+
const now = new Date().toISOString();
|
|
8
|
+
return { status: 'failed', started: false, startedAt: null, finishedAt: now,
|
|
9
|
+
exitCode: null, signal: null, timedOut: false, outputLimitExceeded: false,
|
|
10
|
+
durationMs: 0, stdoutSha256: sha256(''), stderrSha256: sha256(''), capturedBytes: 0, droppedBytes: 0,
|
|
11
|
+
notStartedReason: beforeLaunch ? 'prelaunch-check' : 'supervisor-prelaunch' };
|
|
12
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { canonical, sha256 } from './local-integrity.mjs';
|
|
2
|
+
import { buildInvocation } from './remote-client.mjs';
|
|
3
|
+
import { requestTransport, parseTransportResponse } from './remote-transport.mjs';
|
|
4
|
+
import { ideClientHeaders } from './ide-presentation.mjs';
|
|
5
|
+
import { consumeRecovery } from './local-recovery-budget.mjs';
|
|
6
|
+
import { saveObservationState } from './workflow-observation-state.mjs';
|
|
7
|
+
import { authorizeObservation } from './workflow-observation-remote.mjs';
|
|
8
|
+
import { observationFail } from './workflow-observation-wire.mjs';
|
|
9
|
+
|
|
10
|
+
export async function recoverInterruptedObservation(original, admission, state, location, dependencies) {
|
|
11
|
+
// A missing result, expired lease or absent PID is never evidence of no effects.
|
|
12
|
+
consumeRecovery(state, 'status');
|
|
13
|
+
await saveObservationState(location, state);
|
|
14
|
+
await authorizeObservation(admission, dependencies, false);
|
|
15
|
+
const requestId = buildInvocation('member-observation-admit', original).requestId;
|
|
16
|
+
if (state.admitted.requestId && state.admitted.requestId !== requestId) observationFail('Interrupted observation lost its original request binding');
|
|
17
|
+
const url = `/api/skill/status/${requestId}`, token = await dependencies.readCredential(dependencies.home);
|
|
18
|
+
const response = await requestTransport(dependencies.apiOrigin(), url, { headers: {
|
|
19
|
+
authorization: `Bearer ${token}`, ...ideClientHeaders() } });
|
|
20
|
+
const result = parseTransportResponse(response, 'original interrupted observation admission');
|
|
21
|
+
if (!response.ok || result?.output?.requestId !== requestId || !result.output.admission || !['reported', 'succeeded'].includes(result.output.status)
|
|
22
|
+
|| sha256(canonical(result.output.admission)) !== sha256(canonical(admission))) {
|
|
23
|
+
throw Object.assign(new Error('Original interrupted observation admission remains unavailable; never replay its POST or process'),
|
|
24
|
+
{ code: 'ENTROROVE_LOCAL_OBSERVATION_UNKNOWN', outcomeUnknown: true, requestId });
|
|
25
|
+
}
|
|
26
|
+
state.interruptedRecovery = { schemaVersion: 'entrorove.observation-recovery/1.0', requestId,
|
|
27
|
+
observationId: admission.observationId, admissionDigest: sha256(canonical(admission)), method: 'GET',
|
|
28
|
+
checkedAt: new Date().toISOString(), processResultAvailable: false, effects: 'unknown' };
|
|
29
|
+
await saveObservationState(location, state);
|
|
30
|
+
return { schemaVersion: 'entrorove.local-observation-connection/1.0', status: 'blocked',
|
|
31
|
+
code: 'ENTROROVE_LOCAL_OBSERVATION_RECOVERY_REQUIRED', flowId: admission.flowId,
|
|
32
|
+
observationId: admission.observationId, requestId, independentValidation: 'pending',
|
|
33
|
+
grantsExecutionAuthority: false, grantsMutationAuthority: false, grantsValidatorAuthority: false,
|
|
34
|
+
localProcessMayRestart: false, repeatPost: false, effects: 'unknown', automaticRetryAllowed: false,
|
|
35
|
+
recovery: { method: 'GET', url, originalAdmissionVerified: true, processResultAvailable: false,
|
|
36
|
+
budget: structuredClone(state.recovery) },
|
|
37
|
+
ownerDecision: { required: true, automatic: false, operation: 'flow-cancel',
|
|
38
|
+
input: { flowId: admission.flowId, reason: 'Original observation interrupted without a recoverable process result; effects remain unknown' },
|
|
39
|
+
grantsExecutionAuthority: false, grantsMutationAuthority: false,
|
|
40
|
+
instruction: 'Reconcile the original external effects or ask the original owner to cancel this blocked flow while preserving its unknown history. Cancellation is not acceptance, restoration or permission to rerun.' },
|
|
41
|
+
message: 'The original admission was recovered read-only. Its process result is unavailable; preserve the unknown effects and obtain an explicit owner disposition, without repeating the command.' };
|
|
42
|
+
}
|
|
@@ -7,6 +7,7 @@ import { disciplineRepositoryObservation, disciplineRepositoryDifferences } from
|
|
|
7
7
|
import { runApprovedProcess } from './local-approved-process.mjs';
|
|
8
8
|
import { observationAdmission, observationFail } from './workflow-observation-wire.mjs';
|
|
9
9
|
import { saveObservationState } from './workflow-observation-state.mjs';
|
|
10
|
+
import { notStartedProcess } from './workflow-observation-interruption.mjs';
|
|
10
11
|
|
|
11
12
|
async function observeFile(input, expected) {
|
|
12
13
|
const before = await scopeTarget(input.repositoryRoot, expected.path, false, true);
|
|
@@ -32,8 +33,9 @@ async function executable(admission) {
|
|
|
32
33
|
const same = (before, after) => canonical(before) === canonical(after);
|
|
33
34
|
async function remains(action, expected) { try { return same(expected, await action()); } catch { return false; } }
|
|
34
35
|
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]]))
|
|
36
|
+
return { ...Object.fromEntries(['status', 'started', 'startedAt', 'finishedAt', 'exitCode', 'signal', 'timedOut',
|
|
37
|
+
'outputLimitExceeded', 'durationMs', 'stdoutSha256', 'stderrSha256', 'capturedBytes', 'droppedBytes'].map(key => [key, process[key]])),
|
|
38
|
+
...(process.notStartedReason ? { notStartedReason: process.notStartedReason } : {}) };
|
|
37
39
|
}
|
|
38
40
|
async function execute(input, admission, state, location, options) {
|
|
39
41
|
if (state.run) observationFail('Original local observation already started or has an unknown outcome; a new process is forbidden');
|
|
@@ -45,7 +47,7 @@ async function execute(input, admission, state, location, options) {
|
|
|
45
47
|
observationAdmission(admission, input);
|
|
46
48
|
state.run = { phase: 'running', pid: process.pid, startedAt: new Date().toISOString() };
|
|
47
49
|
await saveObservationState(location, state);
|
|
48
|
-
let processResult;
|
|
50
|
+
let processResult, beforeLaunch = true;
|
|
49
51
|
try {
|
|
50
52
|
await assertBudgetRunnerAllowed(input);
|
|
51
53
|
if (!same(originalSources, await files(input, admission.sourceManifest))
|
|
@@ -54,14 +56,19 @@ async function execute(input, admission, state, location, options) {
|
|
|
54
56
|
observationAdmission(admission, input);
|
|
55
57
|
if (options.authorize) await options.authorize();
|
|
56
58
|
observationAdmission(admission, input);
|
|
59
|
+
beforeLaunch = false;
|
|
57
60
|
processResult = await runApprovedProcess({ root: input.repositoryRoot, policy: admission.command,
|
|
58
61
|
objectPlan: true, startDeadlineAt: admission.expiresAt });
|
|
59
62
|
} catch (error) {
|
|
60
63
|
if (!error?.execution?.process) {
|
|
61
|
-
|
|
62
|
-
|
|
64
|
+
processResult = notStartedProcess(error, beforeLaunch);
|
|
65
|
+
if (!processResult) {
|
|
66
|
+
state.run.phase = 'aborted'; await saveObservationState(location, state);
|
|
67
|
+
observationFail('Local observation stopped without a completed process; its effects remain unknown and execution cannot repeat');
|
|
68
|
+
}
|
|
69
|
+
} else {
|
|
70
|
+
processResult = error.execution.process;
|
|
63
71
|
}
|
|
64
|
-
processResult = error.execution.process;
|
|
65
72
|
}
|
|
66
73
|
let after = before, budgetAllowed = true;
|
|
67
74
|
try { await assertBudgetRunnerAllowed(input); after = (await disciplineRepositoryObservation(input, input.repositoryRoot)).comparison; }
|