@entrorove/skill 0.1.35 → 0.1.36
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 +1 -1
- package/CHANGELOG.md +5 -0
- package/SKILL.md +2 -2
- package/automatic-feedback-client.mjs +35 -0
- package/cloud-watch-client.mjs +5 -1
- package/ide-presentation.mjs +2 -1
- package/manifest.json +1 -1
- package/native-client.mjs +4 -1
- package/package.json +1 -1
- package/release-state.json +10 -10
- package/releases.json +6 -0
- package/remote-client.mjs +2 -1
- package/remote-transport.mjs +3 -1
package/CAPABILITY-MAP.md
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
| 实际进度必须进入 IDE | `cloud-watch` 订阅本人任务 SSE,输出独立 IDE 事件;调用方必须把公开消息和摘要展示到对话进度 |
|
|
24
24
|
| 执行提示与推广可见 | `智能执行中,请勿关闭!` 与服务端选中的真实推广独立输出;保留推广 HTTPS 链接,按事件 ID 去重 |
|
|
25
25
|
| 断线恢复原任务 | `cloud-watch` 带原 `taskId/afterId` 只读续接;`status` 与 `feedback` 查询原请求,不重发业务 POST |
|
|
26
|
-
|
|
|
26
|
+
| 调用结束立即确认评价回传 | 调用完成事务保存本人原 request 的评价与结果摘要;CLI 核验后立即回传原回执身份,服务端返回 IDE 接收确认,不重复写评价或计用量;只读恢复保留原执行代次 |
|
|
27
27
|
| 未验证不可记好评 | intake、模型摘要、reported、不完整证据无评分;阻断、失败、P0/P1 不产生好评;发现和状态查询不生成新评价 |
|
|
28
28
|
| 实际 IDE 与原调用绑定 | `ENTROROVE_IDE` 或宿主检测写入原调用标签;每个 OS 用户继续复用受限凭据存储 |
|
|
29
29
|
| 最新官方技能说明生效 | 新调用使用 `npx --yes --prefer-online @entrorove/skill@latest`;安装更新后重新读取 managed `SKILL.md` |
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.36 — 2026-10-13
|
|
4
|
+
|
|
5
|
+
- 技能调用结束立即确认 IDE 评价回传,提供原账号、原调用与执行代次绑定的接收回执;完善原回执只读恢复与公开合同校验。
|
|
6
|
+
- Confirmed IDE evaluation acknowledgements immediately after skill calls, bound reception receipts to the original account, invocation and generation, and improved read-only recovery and published contract validation.
|
|
7
|
+
|
|
3
8
|
## 0.1.35 — 2026-10-13
|
|
4
9
|
|
|
5
10
|
- 新增协作状态查询、Aimlock 专用规划与八域原生调用;接入账号和设备隔离的任务通知,修复失败接续的评价回执冲突,并完善范围门禁接续。
|
package/SKILL.md
CHANGED
|
@@ -5,7 +5,7 @@ description: An engineering skill that understands a task, chooses a fitting wor
|
|
|
5
5
|
|
|
6
6
|
# entrorove · 熵巡
|
|
7
7
|
|
|
8
|
-
Version: 0.1.
|
|
8
|
+
Version: 0.1.36.
|
|
9
9
|
|
|
10
10
|
Read the user's goal and repository instructions first. Preserve the original task through planning, execution and verification. Use the workflow only where it helps; a small, low-risk edit can proceed directly. Never claim a reported step is a verified result.
|
|
11
11
|
|
|
@@ -87,7 +87,7 @@ The website's signed-in bell control enables encrypted Web Push for the current
|
|
|
87
87
|
|
|
88
88
|
### Automatic invocation evaluation and optional user reviews
|
|
89
89
|
|
|
90
|
-
Every completed or failed execution call receives a server-generated `feedback` receipt bound to the original account, request hash and result digest. Durable calls commit this evaluation in the same transaction as the result;
|
|
90
|
+
Every completed or failed execution call receives a server-generated `feedback` receipt bound to the original account, request hash and result digest. Durable calls commit this evaluation in the same transaction as the result; domain adapters return an idempotent receipt with the same HTTP response. The CLI verifies the original identity and evaluation digest, then immediately returns that exact receipt identity to the authenticated acknowledgement endpoint before finishing the call. Cloud watches do the same as soon as the original evaluation is available. A confirmed `acknowledgement` records the IDE and server reception time without changing the evaluation or counting another invocation. Preserve `receiptId`, `requestId` and `evaluation.digest`; never generate a score or comment locally. Immediately display the confirmed evaluation acknowledgement in visible IDE commentary before the task's final answer, deduplicated by receipt ID. Tool output alone is insufficient. Say “已回传” only with a confirmed acknowledgement; an upload failure must remain visible and cannot become successful feedback. Read the saved receipt with `npx @entrorove/skill feedback <original requestId>` after a connection loss; this is GET only and never repeats execution or submits another evaluation. An authorized retry before side effects keeps the original request but gets a new server execution generation and immutable receipt. Default feedback reads the latest generation; `feedback <original requestId> <generation>` reads a preserved earlier receipt. Never overwrite a failed receipt or use it as the current retry result. Discovery/status queries create no evaluations.
|
|
91
91
|
|
|
92
92
|
Only server-verified progress or a validated pure operation earns a positive automatic evaluation. Reported steps, intake, model summaries and incomplete evidence remain `pending` with no score. Blocked/failed results and P0/P1 findings cannot become positive. These are private technical evaluations; they do not create a public user review or masquerade as the user's words. If a server advertising this extension returns no valid receipt, show the missing receipt and query its original ID. Do not silently claim that evaluation was reported.
|
|
93
93
|
|
|
@@ -43,3 +43,38 @@ export async function queryAutomaticFeedback(requestId, dependencies, generation
|
|
|
43
43
|
if (!response.ok) throw new Error(`Automatic feedback unavailable: HTTP ${response.status}; requestId=${requestId}`);
|
|
44
44
|
return verifyAutomaticFeedback(result.feedback,requestId);
|
|
45
45
|
}
|
|
46
|
+
|
|
47
|
+
function confirmedAcknowledgement(value, original, expectedIde) {
|
|
48
|
+
verifyAutomaticFeedback(value,original.requestId,original.requestHash);
|
|
49
|
+
const ack = value.acknowledgement, generation = original.generation ?? 1;
|
|
50
|
+
if (value.receiptId !== original.receiptId || value.resultDigest !== original.resultDigest
|
|
51
|
+
|| value.evaluation.digest !== original.evaluation.digest || (value.generation ?? 1) !== generation
|
|
52
|
+
|| !ack || ack.schemaVersion !== 'entrorove.feedback-acknowledgement/1.0' || ack.stored !== true
|
|
53
|
+
|| ack.receiptId !== original.receiptId || ack.requestId !== original.requestId || ack.generation !== generation
|
|
54
|
+
|| typeof ack.ide !== 'string' || !/^[\p{L}\p{N} .+_-]{2,48}$/u.test(ack.ide)
|
|
55
|
+
|| expectedIde && ack.ide !== expectedIde || !Number.isFinite(Date.parse(ack.receivedAt))) {
|
|
56
|
+
throw new Error(`IDE feedback is not confirmed; query feedback ${original.requestId}. Do not repeat the invocation.`);
|
|
57
|
+
}
|
|
58
|
+
return value;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export async function acknowledgeAutomaticFeedback(feedback, origin, token, ideHeaders) {
|
|
62
|
+
verifyAutomaticFeedback(feedback,feedback.requestId,feedback.requestHash);
|
|
63
|
+
if (feedback.acknowledgement) return confirmedAcknowledgement(feedback,feedback);
|
|
64
|
+
const route = `/api/skill/feedback/${feedback.requestId}`;
|
|
65
|
+
const headers = { authorization: `Bearer ${token}`,...ideHeaders };
|
|
66
|
+
let response;
|
|
67
|
+
try {
|
|
68
|
+
response = await requestTransport(trustedOrigin(origin),`${route}/ack`, { method: 'POST',
|
|
69
|
+
headers: { ...headers,'content-type': 'application/json' },body: JSON.stringify({ receiptId: feedback.receiptId,
|
|
70
|
+
requestHash: feedback.requestHash,resultDigest: feedback.resultDigest,evaluationDigest: feedback.evaluation.digest,
|
|
71
|
+
generation: feedback.generation ?? 1 }) });
|
|
72
|
+
} catch (cause) {
|
|
73
|
+
if (!cause.established) throw new Error(`IDE feedback was not sent; query feedback ${feedback.requestId}. Do not repeat the invocation.`);
|
|
74
|
+
// A lost acknowledgement response is recovered only by reading this
|
|
75
|
+
// immutable receipt. Neither the execution nor its acknowledgement POST is replayed.
|
|
76
|
+
response = await requestTransport(trustedOrigin(origin),`${route}?generation=${feedback.generation ?? 1}`, { headers });
|
|
77
|
+
}
|
|
78
|
+
if (!response.ok) throw new Error(`IDE feedback acknowledgement failed: HTTP ${response.status}; query feedback ${feedback.requestId}. Do not repeat the invocation.`);
|
|
79
|
+
return confirmedAcknowledgement(parseTransportResponse(response,'IDE feedback acknowledgement').feedback,feedback,ideHeaders?.['x-entrorove-ide']);
|
|
80
|
+
}
|
package/cloud-watch-client.mjs
CHANGED
|
@@ -2,6 +2,7 @@ import { trustedOrigin } from './remote-transport.mjs';
|
|
|
2
2
|
import { consumeCloudStream } from './cloud-event-stream.mjs';
|
|
3
3
|
import { automaticFeedbackIdeEvent, cloudIdeEvent, displayIdeEvent, ideClientHeaders } from './ide-presentation.mjs';
|
|
4
4
|
import { queryCloudTask } from './cloud-task-client.mjs';
|
|
5
|
+
import { acknowledgeAutomaticFeedback } from './automatic-feedback-client.mjs';
|
|
5
6
|
|
|
6
7
|
const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
7
8
|
function inputOptions(input) {
|
|
@@ -49,7 +50,10 @@ export async function watchCloudTask(input, dependencies) {
|
|
|
49
50
|
message: '云端沙箱输出完毕;实际验证状态以任务回执为准。',separateLine: true });
|
|
50
51
|
const current = await queryCloudTask(taskId,dependencies);
|
|
51
52
|
if (current.status === 'observed') taskStatus = current.taskStatus;
|
|
52
|
-
if (current.feedback)
|
|
53
|
+
if (current.feedback) {
|
|
54
|
+
current.feedback = await acknowledgeAutomaticFeedback(current.feedback,dependencies.apiOrigin(),token,ideClientHeaders());
|
|
55
|
+
emit(automaticFeedbackIdeEvent(current.feedback));
|
|
56
|
+
}
|
|
53
57
|
emit({ schemaVersion: 'entrorove.ide-event/1.0',taskId,kind: 'status',phase: 'exit',
|
|
54
58
|
message: settled || taskStatus !== 'running' ? '云端沙箱正在退出本次进度订阅' : '云端沙箱仍在执行,下次从当前进度继续读取',separateLine: true });
|
|
55
59
|
return { schemaVersion: 'entrorove.cloud-watch/1.0',status: current.status,taskId,taskStatus,afterId,outputAvailable,
|
package/ide-presentation.mjs
CHANGED
|
@@ -60,5 +60,6 @@ export function automaticFeedbackIdeEvent(feedback) {
|
|
|
60
60
|
const status = disposition === 'good' ? '当前调用验证通过' : disposition === 'bad'
|
|
61
61
|
? '当前调用被阻断或验证失败' : '交付验证尚未完成,暂不评分';
|
|
62
62
|
return { schemaVersion: 'entrorove.ide-event/1.0',requestId: feedback.requestId,receiptId: feedback.receiptId,
|
|
63
|
-
kind: 'evaluation',phase: 'feedback',disposition,
|
|
63
|
+
kind: 'evaluation',phase: 'feedback',disposition,
|
|
64
|
+
message: `${feedback.acknowledgement?.stored === true ? '本次调用评价已回传至服务器' : '服务器已保存本次调用评价'}:${status}。`,separateLine: true };
|
|
64
65
|
}
|
package/manifest.json
CHANGED
package/native-client.mjs
CHANGED
|
@@ -41,7 +41,10 @@ export async function invokeNativeResult(domain, operation, input, dependencies)
|
|
|
41
41
|
const found = discovery.result.output;
|
|
42
42
|
const extension = (found.capabilities ?? found).responseExtensions;
|
|
43
43
|
if (extension?.automaticFeedback === 'entrorove.automatic-feedback/1.0') feedbackRequired = !extension.automaticFeedbackObservations.includes(operation);
|
|
44
|
-
|
|
44
|
+
// JSON Schema permits object keywords without an adjacent type keyword.
|
|
45
|
+
// Validate their actual semantics rather than rejecting the published
|
|
46
|
+
// contract through Ajv's optional strictTypes authoring convention.
|
|
47
|
+
const ajv = new Ajv({ strict: true, strictRequired: false, strictTypes: false, allErrors: true });
|
|
45
48
|
ajv.addKeyword({ keyword: 'optional', schemaType: 'boolean', valid: true });
|
|
46
49
|
ajv.addFormat('uuid', /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i);
|
|
47
50
|
ajv.addFormat('date-time', value => Number.isFinite(Date.parse(value)));
|
package/package.json
CHANGED
package/release-state.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "entrorove.release-state/1.0",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"digest": "
|
|
3
|
+
"version": "0.1.36",
|
|
4
|
+
"digest": "31125fc03752d64a87f994186ebf770a40966984d65a99358239ef71ab926723",
|
|
5
5
|
"files": {
|
|
6
6
|
"local-final-gate16.mjs": "b30caab08441449ad556a6e9a3cefbf91190f0b3f7370f46d2a21156375aa8e3",
|
|
7
7
|
"local-final-gate16-checks.mjs": "1dd30e9666d458d8b12ca6e4975f6f0ac8450c3ea9cbecc7401ae037f66b589a",
|
|
@@ -47,8 +47,8 @@
|
|
|
47
47
|
"cli.mjs": "f0a3104ef9f4431ded2a7049c08ae6435b09ed53c4cba486c2bd52db2728d999",
|
|
48
48
|
"review-client.mjs": "3491eef68ed533174b31db3c53febb6519b8f088f71a9964644714a9a4c03c77",
|
|
49
49
|
"version.mjs": "1f392147d72c40af4b03b307ea607075fb815af5174fa07e254b95fe12dbf3e7",
|
|
50
|
-
"SKILL.md": "
|
|
51
|
-
"CAPABILITY-MAP.md": "
|
|
50
|
+
"SKILL.md": "f06fd87e2008e5951c778c2e206cb42eed668d21d5c0f2a12108a0a031fde9ad",
|
|
51
|
+
"CAPABILITY-MAP.md": "40755edd3c698bbbbd4f49bc47a21c5ad9bbb8eb05e9542dd7d3a11a0254ea35",
|
|
52
52
|
"AGREEMENT.md": "f93a68e92c457200dd024610e65f74e478b8f60860f951da818b70561f1b9bf8",
|
|
53
53
|
"package.json": "9a7f12414556bcc150d57e64881694aeddfe0b760e98454491ac5a6585ed0421",
|
|
54
54
|
"manifest.json": "ab06e307795bc9da5add926752b6c4dbdaf18625090261a035aa356a679c504f",
|
|
@@ -118,17 +118,17 @@
|
|
|
118
118
|
"local-scope-state.mjs": "8b600a91fc0068d7a8c0bb752ddba7ed30ada93daafb118d6cba2368fd94cb27",
|
|
119
119
|
"local-scope-workspaces.mjs": "a44c34537e5ed2dcaf193a985e5bc05957989fbb160a650f9e37ba7d66eb2de8",
|
|
120
120
|
"local-task-routing.mjs": "e26d6f1ba134ffe1da2a49b4fb6bb6dfa5617671f774a08e719d04f202cf5eca",
|
|
121
|
-
"remote-client.mjs": "
|
|
121
|
+
"remote-client.mjs": "886ca19718b1d23209807ee3ce7d336053a17c0ad2190bb71f4c96371694dff4",
|
|
122
122
|
"cloud-task-client.mjs": "ecb6124ea5e6249f31fb95cb68d13d821d2daea8768fe47ddf6dcf82fc3392cc",
|
|
123
123
|
"scope-runner-client.mjs": "646ab4f80d4a8209e922fd45f40efd968f0744d9dfc03188b222c1a2e11e83b8",
|
|
124
|
-
"native-client.mjs": "
|
|
124
|
+
"native-client.mjs": "ea4d9c687b62858dc4e8fb6bceca59bb049cba0c2762380be460821393e025db",
|
|
125
125
|
"native-notification.mjs": "f116772178140d1a2a7aac4a8e361a76543b1f47c84b3823a26a797f11a8bfbb",
|
|
126
126
|
"local-peer-status.mjs": "a971bcc69d60bb32b875ca5bb4297d948631d5d2821b812c279613ea059a8b4f",
|
|
127
|
-
"cloud-watch-client.mjs": "
|
|
127
|
+
"cloud-watch-client.mjs": "f9629e67d1f14f50e9fb52f65001059e07999352fb224b7c7e28590b95609a8a",
|
|
128
128
|
"cloud-event-stream.mjs": "e0eec9fc3e0613094523929634f25030df5ca5c5b5fe2c1e1a4586ab10574808",
|
|
129
|
-
"ide-presentation.mjs": "
|
|
130
|
-
"automatic-feedback-client.mjs": "
|
|
131
|
-
"remote-transport.mjs": "
|
|
129
|
+
"ide-presentation.mjs": "d8f54505cf559af98cd1a93a739817c13df3e1e68d2dff9fde90554ea14cb10c",
|
|
130
|
+
"automatic-feedback-client.mjs": "75e92f50d6fbfa4f482af36e16c9ce5dd323a02e99eb9b434dcfa3faa846a532",
|
|
131
|
+
"remote-transport.mjs": "93caaca646fca298a4e08142678b134ecc3a657e00de5b9939e2364b2db9d6c4",
|
|
132
132
|
"local-credential.mjs": "2a302a7f67b5ea8dc73453fc96ab33db349b59ca11fa9456e48ca1d9669d877c",
|
|
133
133
|
"local-invocations.mjs": "f6ac4c41c1a5ec34de358c4cca210ca8e403b3a913150a43bb55ec9be55d9998",
|
|
134
134
|
"local-task-handoff-fence.mjs": "5532a359ee29b885f7ce0cf7178f76dba0fc9245bdd92ef460982275baf0d557",
|
package/releases.json
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.1.36",
|
|
4
|
+
"date": "2026-10-13",
|
|
5
|
+
"zh": "技能调用结束立即确认 IDE 评价回传,提供原账号、原调用与执行代次绑定的接收回执;完善原回执只读恢复与公开合同校验。",
|
|
6
|
+
"en": "Confirmed IDE evaluation acknowledgements immediately after skill calls, bound reception receipts to the original account, invocation and generation, and improved read-only recovery and published contract validation."
|
|
7
|
+
},
|
|
2
8
|
{
|
|
3
9
|
"version": "0.1.35",
|
|
4
10
|
"date": "2026-10-13",
|
package/remote-client.mjs
CHANGED
|
@@ -2,7 +2,7 @@ import { createHash } from 'node:crypto';
|
|
|
2
2
|
import Ajv from 'ajv';
|
|
3
3
|
import { parseTransportResponse, requestTransport, trustedOrigin } from './remote-transport.mjs';
|
|
4
4
|
import { appendInvocation } from './local-invocations.mjs';
|
|
5
|
-
import { verifyAutomaticFeedback } from './automatic-feedback-client.mjs';
|
|
5
|
+
import { acknowledgeAutomaticFeedback, verifyAutomaticFeedback } from './automatic-feedback-client.mjs';
|
|
6
6
|
import { ideClientHeaders, presentInvocationNotices } from './ide-presentation.mjs';
|
|
7
7
|
|
|
8
8
|
export const apiUrl = 'https://entrorove.com/api/skill/invoke';
|
|
@@ -135,6 +135,7 @@ export async function postInvocation(call, token, home, feedbackRequired = false
|
|
|
135
135
|
const expected = call.feedbackHashes ?? [call.requestId];
|
|
136
136
|
if (!expected.includes(result.feedback.requestHash)) throw new Error('Automatic feedback lost its original invocation binding');
|
|
137
137
|
verifyAutomaticFeedback(result.feedback,call.requestId,result.feedback.requestHash);
|
|
138
|
+
result.feedback = await acknowledgeAutomaticFeedback(result.feedback,new URL(call.url).origin,token,ideClientHeaders());
|
|
138
139
|
}
|
|
139
140
|
else if (feedbackRequired && !['running','pending'].includes(result.output.status)) {
|
|
140
141
|
throw new Error(`Automatic feedback receipt is missing; query feedback ${call.requestId}. Do not repeat the invocation.`);
|
package/remote-transport.mjs
CHANGED
|
@@ -57,8 +57,10 @@ export async function requestTransport(origin, pathname, options = {}) {
|
|
|
57
57
|
const trusted = trustedOrigin(origin);
|
|
58
58
|
if (typeof pathname !== 'string' || !pathname.startsWith('/api/') || pathname.includes('://')) throw new Error('Invalid Entrorove API path');
|
|
59
59
|
const url = new URL(pathname, trusted);
|
|
60
|
-
if (url.origin !== trusted || url.search || url.hash) throw new Error('Invalid Entrorove API path');
|
|
61
60
|
const configured = { timeoutMs: 15_000, method: 'GET', ...options };
|
|
61
|
+
const originalGeneration = configured.method === 'GET' && /^\/api\/skill\/feedback\/[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(url.pathname)
|
|
62
|
+
&& /^\?generation=[1-9][0-9]{0,14}$/.test(url.search) && Number.isSafeInteger(Number(url.searchParams.get('generation')));
|
|
63
|
+
if (url.origin !== trusted || url.hash || url.search && !originalGeneration) throw new Error('Invalid Entrorove API path');
|
|
62
64
|
if (!['GET', 'POST'].includes(configured.method)) throw new Error('Invalid Entrorove transport method');
|
|
63
65
|
for (let number = 1; number <= 3; number++) {
|
|
64
66
|
try {
|