@entrorove/skill 0.1.37 → 0.1.38
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 +11 -0
- package/CHANGELOG.md +5 -0
- package/IDE-EXECUTION.md +93 -0
- package/REUSE-DISCIPLINE.md +18 -0
- package/SKILL.md +22 -93
- package/cli.mjs +11 -7
- package/cloud-task-client.mjs +3 -1
- package/ide-code-mode.mjs +38 -0
- package/ide-command.mjs +76 -0
- package/ide-hook.mjs +167 -0
- package/ide-install.mjs +59 -0
- package/ide-presentation.mjs +6 -0
- package/ide-results.mjs +59 -0
- package/ide-session.mjs +86 -0
- package/local-approved-plan.mjs +21 -6
- package/local-archguard-ast.mjs +6 -1
- package/local-archguard-language-ast.mjs +7 -0
- package/local-cli.mjs +6 -1
- package/local-contracts.mjs +4 -1
- package/local-discipline-actions.mjs +71 -0
- package/local-discipline-analysis.mjs +153 -0
- package/local-discipline-batch.mjs +32 -0
- package/local-discipline-contracts.d.mts +6 -0
- package/local-discipline-contracts.mjs +62 -0
- package/local-discipline-gate.mjs +85 -0
- package/local-discipline-native.mjs +33 -0
- package/local-discipline-operations.mjs +39 -0
- package/local-discipline-repository.mjs +87 -0
- package/local-discipline-snapshot.mjs +29 -0
- package/local-equivalence-runner.mjs +33 -0
- package/local-error.mjs +10 -0
- package/local-execution.mjs +1 -0
- package/local-integrity.d.mts +5 -0
- package/local-integrity.mjs +4 -0
- package/local-merge-controller.mjs +1 -0
- package/local-merge-rollback.mjs +2 -1
- package/local-mutation-authority.mjs +16 -7
- package/local-mutation-batch.mjs +7 -3
- package/local-mutation-files.mjs +22 -0
- package/local-mutation-snapshot.mjs +6 -3
- package/local-mutation-wire.mjs +6 -1
- package/local-runner-discipline.mjs +23 -0
- package/local-scope-repository.mjs +16 -0
- package/local-task-handoff-write-receipts.mjs +11 -0
- package/manifest.json +1 -1
- package/package.json +33 -4
- package/release-state.json +55 -28
- package/release.mjs +3 -1
- package/releases.json +6 -0
- package/remote-client.mjs +8 -0
- package/reuse-discipline-release.mjs +18 -0
- package/runtime/validator-runtime-v7.0.44.d.mts +3 -0
- package/runtime/validator-runtime-v7.0.44.mjs +1362 -0
- package/snapshot-cleanup-journal.mjs +32 -0
- package/snapshot-retention.mjs +95 -0
- package/task-entry-client.mjs +2 -2
- package/validator-runtime-build.mjs +16 -0
package/CAPABILITY-MAP.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# 能力对账图(WP-02 / AC-20)
|
|
2
2
|
|
|
3
|
+
## 2026-10-14 接入:受控执行与复用一致性
|
|
4
|
+
|
|
5
|
+
| 能力 | 正常公开入口 | 验证与边界 |
|
|
6
|
+
| --- | --- | --- |
|
|
7
|
+
| IDE 工具守卫 | `install`、Codex `/hooks` 审核 | 原任务编号跨回合与压缩保留;未验收阻止结束,拒绝原生写入及失败后换执行器。配置安装与真实宿主信任分别验收,其它 IDE 的守卫尚未接入 |
|
|
8
|
+
| 变更纪律 | `local discipline-review/discipline-check/guarded-delete/guarded-move`、`workflow-discipline-review` | 单一事实源、用途三态、全仓差集、已签名变更分类及原账号确认;删除数据需要绑定实际快照证据。未知用途保持未知,阈值仍待实测 |
|
|
9
|
+
| 并行路径等价 | `local run-approved-plan`、Validator 7.0.44 | 固定基线来自本项目既有路径的实际输出;逐字段比对,缺证据不得 pass,差异列出字段。不是其它项目的历史输出 |
|
|
10
|
+
| 结束清理与回传 | 原请求 `continue`、`workflow-verdict`、反馈确认 | 仅验证完成且回传已存后清理同流程冗余快照,保留原始及最新恢复点;公开技术评分按真实已确认回执聚合 |
|
|
11
|
+
|
|
12
|
+
本次仍不提供任务优先级队列、插入任务结束后自动恢复父任务或无人值守唤醒。这些需要后续单独实现和验收。源代码执行仍需原合同配置的可信运行器,范围签名器本身不授予执行权限。
|
|
13
|
+
|
|
3
14
|
## 2026-10-13 接入:协作观测、原生规划与任务通知
|
|
4
15
|
|
|
5
16
|
| 能力 | 正常公开入口 | 已执行验证与边界 |
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.38 — 2026-10-14
|
|
4
|
+
|
|
5
|
+
- 新增需宿主信任的 Codex 工具守卫,保留原任务和请求编号;接入确定性复用纪律、用途审查、变更分类、逐字段等价与全仓差集验收;仅验证完成并回传后清理冗余快照,按真实回执展示技术评分;更新日志每页 5 条。
|
|
6
|
+
- Added a Codex tool guard requiring host trust and preserving original task identities; enforce deterministic reuse, usage review, declared mutations, field equivalence and repository differences. Clean redundant snapshots only after verified completion and acknowledged feedback; display ratings from actual acknowledgements and five changelog entries per page.
|
|
7
|
+
|
|
3
8
|
## 0.1.37 — 2026-10-13
|
|
4
9
|
|
|
5
10
|
- 统一 IDE 与网页沙箱任务编号;新任务按账号设置显示云端选择并保留原任务数据,进入及结束通知去重且发送失败可重试;适配 Windows Git 范围元数据检查。
|
package/IDE-EXECUTION.md
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
Install or update the managed copy with `npx @entrorove/skill install`. The installer keeps one global managed entrorove skill, replaces its older pristine version, removes only pristine duplicate installations, and preserves hand-edited files. An older package cannot overwrite a newer managed version.
|
|
2
|
+
|
|
3
|
+
Register or sign in by email at https://entrorove.com. Enter the account key once with `npx @entrorove/skill configure` and `{"token":"..."}` on standard input. The credential persists in the current OS user's restricted local store across skill upgrades. Before asking again, use the stored credential; a missing or invalid credential must be reported explicitly. Never place the key in arguments, URLs, project files or logs. entrorove accounts and keys are independent of other services.
|
|
4
|
+
|
|
5
|
+
Every invocation rereads that same credential file, including clients already running. After an authenticated account page supplies the current key and `configure` synchronizes it once, all tasks under the same OS user automatically use the new value. A revoked or expired key cannot obtain new permissions for itself: return to the authenticated account page and synchronize once through JSON stdin. Status recovery only queries the original request; it never rotates credentials or repeats the operation.
|
|
6
|
+
|
|
7
|
+
On first use or after a material agreement revision, the CLI returns a Confirm Protocol-compatible agreement interaction. Render it with the IDE's native confirmation UI, or show its `chatFallback` text when no adapter exists. The user must explicitly accept with `npx @entrorove/skill agreement` and JSON `{"version":"2026-10-07.1","answer":"accept"}` on standard input before retrying the skill request. A full-access IDE permission never counts as agreement acceptance. The combined terms, privacy and advertising notice is installed as `AGREEMENT.md`.
|
|
8
|
+
|
|
9
|
+
## Work with a task
|
|
10
|
+
|
|
11
|
+
### IDE display and cloud planning entry
|
|
12
|
+
|
|
13
|
+
For a new engineering task, run `npx --yes --prefer-online @entrorove/skill@latest invoke` with `operation: "start"` and the actual task facts below. The CLI reads the authenticated account's sandbox preference before dispatch. An enabled account returns `status: "needs-input"` and a cloud choice, with no model call yet. This is a routing question, not an execution failure. Render it immediately with the host's question tool or native UI; if unavailable, display `interaction.chatFallback` and collect the answer. A collapsed command log is insufficient. Offer **确认** and **退出,采用本地方案**. After confirmation call the returned `cloud-task` callback with its exact original payload and `sandboxChoice: "use"`; exit repeats the original `start` with top-level `sandboxChoice: "local"`. Preserve the original goal, risk, work type and requirements. A disabled account continues through its configured local workflow; unavailable preferences stop entry explicitly. Reuse a prior explicit choice while resuming this task. Silence never authorizes cloud consumption.
|
|
14
|
+
|
|
15
|
+
For an explicit cloud planning request without an existing start, `cloud-task` accepts `{"goal":"<actual goal>","ideTaskId":"<current IDE task ID, when available>"}` on stdin and returns the same choice. Do not start both routes for one task.
|
|
16
|
+
|
|
17
|
+
With `sandboxChoice: "use"` (or the protocol callback's `answer: "use"`), immediately display the returned acceptance message, for example **云端任务 08921 · 已进入**. Use the returned `taskNumber` verbatim: it matches the homepage sandbox tab and notification. Retain the UUID `taskId` separately for API queries; never display the IDE chat ID or invent a number instead. Then run the returned `nextAction`, `cloud-watch`. It subscribes to that account's authoritative SSE stream, returns newline-delimited `entrorove.ide-event/1.0` events, then one `entrorove.cloud-watch/1.0` result. **Mirror each new event's public `message` and optional `detail` into visible IDE progress/commentary.** Deduplicate by task ID and event ID, including the acceptance message repeated in the stream or final result. The same rule applies to normal invocation `ideMessages` and notice events. A JSON field or collapsed command log does not satisfy this display requirement. Show `智能执行中,请勿关闭!` and the selected promotion on separate lines; preserve the promotion's actual HTTPS link. Use only the server's selected promotion; do not insert a local test advertisement.
|
|
18
|
+
|
|
19
|
+
Display the actual entering, allocation, thinking, public output and exit events as they arrive. Do not generate model reasoning, invent intermediate events or replace `reported` with verified completion. The public model summary is the planning output available to show. `云端沙箱输出完毕` means the current planning response has arrived; inspect its real task/verification status before dependent execution. Exit here closes the progress subscription and does not cancel the persisted task.
|
|
20
|
+
|
|
21
|
+
When a bounded watch returns `nextAction`, continue it with the returned `afterId`; reconnect only with GET and that cursor. Never repeat cloud-task POST to recover progress. For an available planning result, query `status <feedback.requestId>` to obtain the original accepted flow and required next step, then continue that flow. Do not create a second `start` for the same cloud goal. If the task is still running but no events arrive, say so and keep reading its real status. Missing credentials, blocked entitlement, expiry and stream errors must be visible.
|
|
22
|
+
|
|
23
|
+
Set `ENTROROVE_IDE` to the actual host name (for example `Codex`, `Cursor` or `Claude Code`) when host detection is unavailable. It carries only the IDE label; credentials remain in the restricted store. Use the latest official package with `--prefer-online` for new invocations, and reread the managed `SKILL.md` after installation reports an update. Recovering an uncertain request remains a read-only query of its original ID.
|
|
24
|
+
|
|
25
|
+
Send JSON on standard input to `npx @entrorove/skill invoke`. Before every execution call, discover `operation: "capabilities"` with `{}` and validate input against the returned operation schema. The CLI performs remote discovery automatically; local adapters discover the installed contract before execution. Discovery failure stops execution. Adapters that expose the four-step task route can call `task-describe`, `message-route`, `message-accept` and `task-resume` in order; `start` remains the one-call workflow equivalent. Then start with `operation: "start"` and an `input.task` containing the goal, work type, risk, difficulty and observed scope facts. Work types are `implementation`, `documentation`, `calculation`, `merge`, `review`, `decision` and `diagnosis`. Assess facts from the real task and repository; do not invent certainty. entrorove chooses the workflow. A small task may return `decision: "direct"`, which skips extra planning round trips. It does not authorize native writes outside the controlled task; keep its executable acceptance assertion and the original mutation authority. The public envelope is `entrorove.skill.request/2.0`; `requestId` is the SHA-256 digest of `operation + canonical(input)`. Version 1.0 remains accepted for older callers.
|
|
26
|
+
|
|
27
|
+
The server's ordinary `start` operation creates a durable skill flow and counts a skill invocation. The IDE CLI routes new starts through the account's preference and explicit task choice described above. A real sandbox is created only by `/api/cloud-task`, which returns both `taskId` and `taskNumber` and counts sandbox usage separately. `local` changes only this task's route. Disabled entitlement or missing model prerequisites stop cloud dispatch; a `needs-input`, `blocked` or `failed` result must never be described as sandbox entry. Do not send a second ordinary `start` after cloud acceptance; continue the original bound flow returned by its watch/status.
|
|
28
|
+
|
|
29
|
+
After dispatch, use `cloud-watch` for live IDE progress and `cloud-status` for a read-only snapshot with `input.taskId`. Both are CLI-only routes, also accepted by `invoke`; they do not pass through `/api/skill/invoke`. Status includes public title/summary, actual model usage and the stored automatic evaluation when available. A missing task is explicit and never treated as completed. The IDE and website consume the same account-bound event stream.
|
|
30
|
+
|
|
31
|
+
### Per-task cloud sandbox choice
|
|
32
|
+
|
|
33
|
+
When the host exposes an enabled cloud-sandbox preference and a new task is about to dispatch a cloud model, ask once whether this task should use the cloud sandbox. This is a low-risk routing preference, separate from agreement acceptance and the medium/high-risk confirmations below. Offer `use for this task` and `continue locally`; if the user gives no answer, continue locally. Cloud submission requires an explicit choice or the user’s existing authorization for this task; silence never authorizes cloud consumption. An explicit opt-out applies only to the current task and must not change the account-wide sandbox preference. Do not ask again while continuing or resuming the same task. If the host cannot preflight the account preference, show the choice only as a routing decision and let the server's authoritative `/api/cloud-task` check return a clear `blocked` prerequisite; never claim that a task started after a blocked response. This choice never bypasses the normal task schema, mutation authority, evidence checks, or risk confirmation.
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{"operation":"start","input":{"task":{"goal":"Update the checkout flow and verify it","workType":"implementation","risk":"medium","difficulty":"medium","crossModule":true,"parallel":false,"unclear":false,"architectureContract":false}}}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
For `workType: "merge"`, include `baselineRef` with the concrete branch, tag, commit, or review baseline used for comparison. The API rejects a merge plan without it, and the baseline must remain unchanged through verification. For `workType: "decision"`, include the structured `interaction`; elevated-risk decisions also require `riskDescription`.
|
|
40
|
+
|
|
41
|
+
The v2 capability map is recorded in [`CAPABILITY-MAP.md`](CAPABILITY-MAP.md). It maps every legacy domain and operation to its v2 equivalent, narrower semantics, or an explicitly documented uncovered area; adapters must not silently substitute an uncovered operation.
|
|
42
|
+
|
|
43
|
+
For an explicit domain operation, use `npx @entrorove/skill native <domain> <operation>` with its input object on stdin. The supported domains are `aimlock`, `blueprint`, `calctool`, `swarm`, `validator`, `mergeguard`, `archguard` and `confirm-protocol`. This public adapter discovers that domain's actual server schema, validates the input, invokes the registered operation once, and verifies any required automatic feedback. Discovery, help and status observations follow the server's published feedback contract. A failed gate or unknown outcome must never be replaced with another executor or reported as local success; fix the original cause and recover the original request through its read-only status.
|
|
44
|
+
|
|
45
|
+
Aimlock exposes `brain-plan`, `brain-check`, `brain-validate` and `brain-status`. Create a plan with the actual goal, scope `contract`, `requirements` and ordered `steps`; retain its returned `requestId` and `plan.digest`. Subsequent operations take only that original `planRequestId` (plus `paths` for `brain-check`); the server loads the authenticated account's stored plan. Never submit a reconstructed plan or another account's request. Planning validation checks scope, requirements and dependencies; it grants no mutation authority and never certifies business delivery.
|
|
46
|
+
|
|
47
|
+
For a returned `flowId`, continue with `{"operation":"continue","input":{"flowId":"<returned ID>","operation":"<next operation>","payload":{}}}`. Fill `payload` with the next operation's required input. Keep the same task and evidence in the IDE. For later work, `input.task.phase` may be `plan`, `coordinate`, `architecture`, `verify`, `merge` or `decision`; it remains the same skill entry point. Never treat an unknown request outcome as permission to retry a paid or mutating action; query the original request ID when the workflow supports it.
|
|
48
|
+
|
|
49
|
+
The v2 progress sequence is durable and ordered: the first runtime step reports `intake`, then the applicability `gate` is recorded and verified, then the selected contract or plan steps run. Every step can be `pending`, `running`, `reported`, `verified`, `blocked` or `failed`; only a completed verdict with trusted evidence is green.
|
|
50
|
+
|
|
51
|
+
When intake returns `workflow-gate`, connect the current repository before invoking that gate: run `npx @entrorove/skill scope-connect <absolute repositoryRoot>` with JSON `{"flowId":"<original flowId>","paths":["<existing source file>"]}` on stdin. Use the concrete existing source files in the task's scope; new files belong in the later plan's declared artifacts. The adapter enrolls an OS-private Ed25519 scope signer for this accepted account and task, answers a server challenge, copies and verifies real source files, and submits the signed facts. It sends hashes and scope metadata rather than source contents or the private key. Enrollment grants scope inspection only; execution evidence and write passes retain their separate authority checks. An operator-configured signer cannot be replaced. After a successful connection, use the returned `nextInput` for `continue`, or explicitly send `payload: {"targetFiles":["<same existing source file>"]}` to the original `workflow-gate`. The connector uses `paths`; the gate uses `targetFiles`. Refresh an expired snapshot by reconnecting the same flow and path set. Show an explicit blocked result; query the original request ID after an unknown transport outcome before considering another attempt.
|
|
52
|
+
|
|
53
|
+
Scope inspection resolves aliases from actual `tsconfig.json` or `jsconfig.json`, including relative `extends`. For plugin source compiled by a host project whose config is outside the source's ancestors, include `importContexts: [{"sourcePrefix":"<plugin source directory>","configPath":"<actual host tsconfig.json>"}]` in `scope-connect` input. Inspect the real build configuration first; never invent an alias or mark an unresolved import as external. These context paths remain inside the repository, their hashes enter the signed facts, and the local task binding freezes them.
|
|
54
|
+
|
|
55
|
+
Keep snapshot before-images distinct from a frozen execution plan's expected final file hashes. Controlled writes consume the original approved authority; the runner then verifies the actual planned final bytes. Never edit a signed plan or silently substitute a newer snapshot after an unknown or failed gate. Existing changes outside that authority require explicit revalidation of the same original flow.
|
|
56
|
+
|
|
57
|
+
Computed runtime imports remain explicitly unresolved with their actual source paths and hashes. A member's scope-only signer may submit these observations to enter restricted planning; the cloud returns `planningOnly: true` and `requires-complete-import-graph-before-mutation`. Do not treat this as full dependency verification, execution permission, or business completion. Resolve the dynamic dependency contract and obtain complete verified facts before mutation; never set `complete` manually or replace the original signer or paths to bypass the restriction.
|
|
58
|
+
|
|
59
|
+
For a decision, include `input.task.interaction` with `type` (`confirm`, `choice`, `multi` or `input`), a `question`, `options` (two or more with unique `id` and `label`, or an empty array for input), and a `callback` containing its `operation` and `payload`. Medium- and high-risk decisions also need a `riskDescription`. The decision waits for an explicit answer; it never chooses a default on timeout.
|
|
60
|
+
|
|
61
|
+
Use `npx @entrorove/skill status <requestId>` after a connection loss. It performs a read-only GET lookup and never resends a POST. Use `npx @entrorove/skill flows` to list recoverable flow steps. A v2 flow has its own `flowId` and progresses through `pending`, `running`, `reported`, `verified`, `blocked` or `failed`; a reported result is not a verified result.
|
|
62
|
+
|
|
63
|
+
The local execution layer is available through `npx @entrorove/skill local <operation> [repositoryRoot]` with a JSON object on standard input. `local capabilities` lists the complete contract, operation groups and `requiresPass` metadata. `local capabilities <group>` filters that same contract. Operations include `snapshot-plan`, `snapshot-verify`, `mutate-gate`, `gate-issue`, `gate-verify`, `guarded-write`, `budget-init`, `budget-context`, `budget-read`, `budget-status`, `budget-extend`, budget renewal confirmation, `peer-coordinate`, `spawn-bind`, `peer-complete`, `lease-verify`, `probe`, `reassess`, execution ledger and virtual branch records, `chain-init`, `chain-resume`, `chain-status`, `chain-answer`, `evidence-sign`, `evidence-verify`, `merge-verified`, `rollback`, `formula-evaluate`, `formula-graph`, `formula-final-gate`, `run-approved-plan` and `final-gate`. State is kept only under `~/.entrorove/`; snapshots never create Git branches or worktrees. Guarded writes require a short-lived Ed25519 pass bound to the flow, step, snapshot digest and path set. Local evidence uses `entrorove.test-evidence/2.0`; unsigned local evidence remains incomplete and verified delivery requires a trusted receipt. Approved plan execution requires a frozen plan, matching approval and unchanged files; without a configured runner signer it reports local evidence as incomplete.
|
|
64
|
+
|
|
65
|
+
Local CLI failures use the machine-readable `entrorove.local-error/1.0` envelope `{schemaVersion,status,code,disposition,message}` on stderr. `status` is `failed` for invalid input or computation errors and `blocked` for missing mutation, lease, snapshot or handoff authority. Formula `add` and `mul` require at least one argument; `div`, `safeDivide` and `percentOf` reject a zero denominator with `DIV_ZERO`. The formula engine declares `round` as half-away-from-zero with two decimal places by default; an engine may declare another `decimalPlaces` value from 0 through 28 in its `roundingPolicy`.
|
|
66
|
+
|
|
67
|
+
### Read-only peer status
|
|
68
|
+
|
|
69
|
+
`local peer-status` observes the original signed worker grant, task and lease, or the registered coordination task/agent/chain/intent binding. It reports only that worker's active, waiting or expired state, own blocked/ready paths and own checkpoint requests. Queries do not issue leases, change ownership, write a coordination journal or grant permission to write. Use `local capabilities` for the exact supported input variants.
|
|
70
|
+
|
|
71
|
+
### Optional task notifications
|
|
72
|
+
|
|
73
|
+
System notifications are disabled until this account explicitly enables them. `npx @entrorove/skill notifications configure` accepts only `{"enabled":true}` or `{"enabled":false}` on stdin; `notifications status` observes the account's setting and `notifications test` submits a generic test only when enabled. macOS and Linux use their existing notification service. Cloud notifications show the same `taskNumber` as the website: one entry and one ending, including a specific model-balance warning. Intermediate steps, promotion, keep-alive and repeated feedback do not repeat notifications. A rejected OS submission is not marked as sent and remains retryable. Settings use the same home and account as the invocation; changing the credential disables the previous account's setting. OS acceptance does not prove that a notification was visibly displayed.
|
|
74
|
+
|
|
75
|
+
The website's signed-in bell control enables encrypted Web Push for the current account and device. Desktop browsers and supported phones use this same push protocol; iPhone requires a Home Screen web app. Ask permission only through the user's enable action. Logout clears the browser binding and subscription. Messages contain only generic task status, with no prompts, credentials, model output or promotion. Delivery retries keep the original event and device binding; expired endpoints and temporary tasks are cleaned up automatically. Never describe an unsupported platform or failed delivery as a successful notification.
|
|
76
|
+
|
|
77
|
+
### Automatic invocation evaluation and optional user reviews
|
|
78
|
+
|
|
79
|
+
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.
|
|
80
|
+
|
|
81
|
+
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.
|
|
82
|
+
|
|
83
|
+
When the user gives an actual evaluation after using the skill, offer to publish that feedback. Only after they explicitly agree to public display under the current notice, send their unchanged words, IDE name and 1–5 rating as JSON on standard input to `npx @entrorove/skill review`, including `invocationRequestId` from their actual successful call, `publicConsent: true` and `noticeVersion: "2026-10-07.1"`. The same account must own that successful call within the last 30 days; a recorded usage event, failed call or unknown result does not qualify. Three public reviews per account per day share one server quota across API replicas. Public output exposes only IDE, rating, original text and time, never account or invocation identity. Never invent, rewrite or infer a review from task completion. The website reads accepted reviews directly from entrorove's independent database.
|
|
84
|
+
|
|
85
|
+
Feedback command example (replace the request ID with the original successful invocation ID, and use only the user’s actual words after explicit public consent):
|
|
86
|
+
|
|
87
|
+
```json
|
|
88
|
+
{"invocationRequestId":"<original successful request ID>","ide":"Codex","rating":5,"comment":"<unchanged user words>","publicConsent":true,"noticeVersion":"2026-10-07.1"}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
Ordinary Windows scope inspection resolves an absolute Git for Windows `git.exe` from its installation or absolute PATH directories, including paths containing spaces. It never invokes `/usr/bin/git` on Windows, a shell wrapper or a Git executable inside the inspected repository. Missing Git gives `ENTROROVE_GIT_UNAVAILABLE` and requires installing Git for Windows before reconnecting the original scope.
|
|
92
|
+
|
|
93
|
+
The fixed Git byte-metering adapter ships hash-pinned precompiled libraries for Darwin and glibc Linux on arm64/x64. It extracts the selected library on first use; it never invokes a C compiler on the user machine. Darwin requires Apple’s trusted Git (Xcode or Command Line Tools), xcrun and codesign; Linux requires the trusted `/usr/bin/git` and glibc. Native comparisons with enforced source-read budgets remain restricted to these platforms. An unsupported native budget adapter returns `ENTROROVE_GIT_READER_UNSUPPORTED`; do not bypass its budget or claim an ordinary Windows inspection verifies that separate capability.
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Existing-system reuse discipline
|
|
2
|
+
|
|
3
|
+
Apply these rules when adding to or changing an existing system. Reuse is assessed inside the current accepted repository; external projects, databases, accounts, sessions and keys are outside scope.
|
|
4
|
+
|
|
5
|
+
- D-1: Before another business mapping or fact definition, search actual definitions and reuse them. Snapshot planning records the whole repository comparison and AST usage review in `discipline-review.json`; its digest is covered by the signed original snapshot. Typed source-entity field mappings use the existing import/alias resolver to identify the same entity, then compare field/value sets. A conflicting second mapping is refused with the existing file and line. An unresolved semantic relation remains unknown. No overlap threshold is invented.
|
|
6
|
+
- D-2: A rewrite must cite a concrete existing defect at file:line. “Clearer”, “more maintainable” and “more general” are not evidence. A necessary sensitive exception is submitted through `continue` → `workflow-discipline-review` on the original planning phase. Display the whole concrete proposal. Approval must be the original account's stored Confirm Protocol answer and audit, never a caller's `accepted:true`.
|
|
7
|
+
- D-3: A parallel path requires frozen `policy.parallelPaths` and actual same-input, fieldwise equivalence evidence. Use the existing GoldenBaseline to pin baseline bytes and source hash. The approved runner reads the baseline and actual process output; the original output cannot be supplied anew by the implementation. Missing evidence yields incomplete, mismatch yields blocked with field names. Baselines come from the existing path's actual independent samples, not the new implementation's self-consistency tests.
|
|
8
|
+
- D-4: `discipline-review` exposes symbols, actual references, unresolved sources, scan scope and artifact digest. States are in-use, unused and unknown. Exported/external or dynamic references remain unknown, including reflective/computed access. Unknown equals in-use for preservation. A deletion must reference the original usage review, named symbols and task requirement; known in-use deletion additionally needs the explicit approved exception. Zero static references alone never prove business removability.
|
|
9
|
+
- D-5: The cloud-signed `disciplinePolicy.writes` declares modify/create/delete/move/format with reason and original requirement IDs. Deletes and moves need independent explicit approval. `guarded-delete` and `guarded-move` compare the exact original declaration and physical baseline before action. Moves record explicit source/destination/digest events. Formatting on unchanged semantic lines is refused. The rollback snapshot is limited to pass paths; `discipline-check` compares the whole repository, including ignored files, excluding only `.git` and `node_modules`. Outside-scope bytes or modes refuse verification. No self-score grants permission.
|
|
10
|
+
- D-6: Future abstractions require concrete named fields from current requirements. Speculative extension justifications without those fields are refused.
|
|
11
|
+
|
|
12
|
+
Pause for an actual same-semantic new definition, existing data/interface semantic change, data deletion/migration/rebuild, or unsubstantiated rewrite. Submit the exact proposal and reasons through the original flow. Existing data actions must pin their actual pre-execution snapshot artifact in the frozen runner manifest. Never delete to “try” a diagnosis.
|
|
13
|
+
|
|
14
|
+
For an independent new file with no same-semantic definition, documentation/comments/copy, or explicit one-off exploratory work, avoid unnecessary review round trips. Keep the current declared scope and run an executable assertion. Unknown size or overlap thresholds cannot enable an exemption: AC-B1 deletion ratio, AC-B2 overlap, AC-B3 small-change size and AC-B4 scan size stay null pending measurement.
|
|
15
|
+
|
|
16
|
+
The write entry accepts complete content and also has separate structural action entries; complete-file replacement still passes actual old/new AST and diff checks. Error disposition `needs-human` exists for original proposal/usage/snapshot approval failures. Usage review is a separate hash-bound artifact reused by write declarations. Equivalence baselines reuse the existing frozen GoldenBaseline; original source hashes and actual baseline bytes are independently checked. Moves use explicit guarded action events, independent of Git rename heuristics. Semantic matching is limited to proven same source-entity mapping contexts; generic field-name overlap is never enough.
|
|
17
|
+
|
|
18
|
+
Claims are limited to observed managed actions: undeclared changes can be detected and retained snapshots can support rollback. Neither static usage nor equivalence proves the business requirement is correct. Report deployment/publication only with actual evidence. Keep first-party files ≤500 lines and functions ≤100 lines; regenerate pinned assets with their generator. Do not create branches/worktrees. Validate the changed units and reverse dependencies; UI changes require light and dark checks.
|
package/SKILL.md
CHANGED
|
@@ -1,106 +1,35 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: entrorove
|
|
3
|
-
description:
|
|
3
|
+
description: Execute an engineering task through Entrorove, preserving its original scope, approvals, cloud task identity and verifiable result across every IDE turn.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# entrorove · 熵巡
|
|
7
7
|
|
|
8
|
-
Version: 0.1.
|
|
8
|
+
Version: 0.1.38.
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Entrorove applies to the whole task once selected. 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
|
|
|
12
|
-
##
|
|
12
|
+
## Required execution
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
1. Install `npx --yes --prefer-online @entrorove/skill@latest install`. The managed installer installs the skill and Codex lifecycle guard. Review and trust Entrorove in Codex `/hooks`; installation alone is not proof that hooks run. New execution from a detected IDE requires the exact live host approval. An unsupported IDE adapter, missing hook callback, missing credential, or failed discovery stops execution explicitly. Do not silently use native tools instead.
|
|
15
|
+
2. Read [IDE-EXECUTION.md](IDE-EXECUTION.md) for the exact entry, cloud callbacks, account agreement and operation contracts. Use the stored account credential; never put it in arguments, URLs, project files, output or fixtures. Entrorove is independent of other systems.
|
|
16
|
+
3. Discover `capabilities`, then invoke `start` with the actual goal, task type, risk and scope facts. An enabled account returns a cloud choice before charging a model. Show that choice visibly using the host question tool. Confirmation calls its original callback; exit adopts the local route for this task. Never treat silence as permission, invent acceptance, or create both routes. Existing explicit authorization for this task persists.
|
|
17
|
+
4. After real cloud acceptance, immediately display **云端任务 <taskNumber> · 已进入**. Preserve `taskNumber` verbatim: it is the homepage sandbox tab number. Keep its UUID `taskId` separately. Run the returned `cloud-watch`, show each real public event and its cursor, and continue the original accepted flow from status. A command log alone is insufficient. No accepted cloud task means no cloud ID or model-execution claim.
|
|
18
|
+
5. For an accepted `flowId`, execute the returned `nextStep` with its required payload. Discover the schema before constructing input. An empty payload is valid only when that operation's schema allows it. Reconnect and refresh only the original flow. A changed snapshot is a binding failure to investigate; do not invent a fresh successful baseline, rebuild a flow to evade it, or remove the old failure.
|
|
19
|
+
6. All governed mutations use the original authority: `local guarded-write`, `local guarded-delete`, `local guarded-move`, or the original frozen approved runner plan. Native patches, scripts, terminal writes, database mutations and unknown MCP operations must not substitute for the controlled entry. **A failed gate or unknown outcome must never be replaced with another executor or reported as local success.** Query the original request read-only, repair the cause, and obtain the original flow's valid authority before proceeding.
|
|
20
|
+
7. Read [REUSE-DISCIPLINE.md](REUSE-DISCIPLINE.md) when modifying an existing system. The comparison baseline is the existing implementation in that same repository. It never means another project, another account, or copying external systems.
|
|
21
|
+
8. Before finishing, submit actual independent execution evidence, run the server's verification and verdict, and display the confirmed evaluation acknowledgement. Preserve `receiptId`, `requestId`, execution generation and evaluation digest. “已回传” requires `acknowledgement.stored: true`. Missing or failed feedback remains visible. Completed verified tasks automatically release superseded Entrorove snapshot copies, preserving origin and final rollback images; active, waiting and unknown tasks retain recovery data.
|
|
15
22
|
|
|
16
|
-
|
|
23
|
+
The Codex guard preserves this binding over subsequent prompts and compaction and denies unsupported native mutations before execution. Hooks are host guardrails, not an operating-system security boundary; unsupported tool paths or a disabled/untrusted hook cannot be described as enforced. An explicit user decision to stop using the skill ends its governance and never becomes verified Entrorove delivery. Do not infer such a decision from quoted screenshots or a service failure.
|
|
17
24
|
|
|
18
|
-
|
|
25
|
+
## Operations and visible progress
|
|
19
26
|
|
|
20
|
-
|
|
27
|
+
- Invoke service operations with JSON stdin to `npx @entrorove/skill invoke` or a host-approved rewritten equivalent.
|
|
28
|
+
- Explicit domains use `native <domain> <operation>`. Domains: aimlock, blueprint, calctool, swarm, validator, mergeguard, archguard, confirm-protocol. Aimlock `brain-plan`, `brain-check`, `brain-validate`, `brain-status` use the original stored plan.
|
|
29
|
+
- At `workflow-gate`, connect the actual repository and exact source paths with `scope-connect`, then use its original `nextInput`. Scope inspection does not grant execution or writes. Dynamic references remain unknown; never set graph completeness manually.
|
|
30
|
+
- `local capabilities` describes scope, snapshot, budget, ownership, mutation, review and evidence contracts. Do not call a guessed operation or construct a local signature in place of cloud authority.
|
|
31
|
+
- Cloud events and homepage progress share the same account-bound stream. Show public entering, allocation, model activity, output and termination as they occur. Show the server-selected promotion and execution notice separately. Deduplicate task/event/receipt IDs; never invent progress or model reasoning.
|
|
32
|
+
- `status`, `cloud-status` and `feedback` recover the original identity with GET only. Never repeat a paid POST to recover an uncertain result.
|
|
33
|
+
- A genuine user review requires their actual unchanged words and explicit public consent. Automatic technical evaluations are server-derived; public technical summaries aggregate acknowledged graded results and contain no account identity or user quotes. Pending evidence has no score.
|
|
21
34
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
## Work with a task
|
|
25
|
-
|
|
26
|
-
### IDE display and cloud planning entry
|
|
27
|
-
|
|
28
|
-
For a new engineering task, run `npx --yes --prefer-online @entrorove/skill@latest invoke` with `operation: "start"` and the actual task facts below. The CLI reads the authenticated account's sandbox preference before dispatch. An enabled account returns `status: "needs-input"` and a cloud choice, with no model call yet. This is a routing question, not an execution failure. Render it immediately with the host's question tool or native UI; if unavailable, display `interaction.chatFallback` and collect the answer. A collapsed command log is insufficient. Offer **确认** and **退出,采用本地方案**. After confirmation call the returned `cloud-task` callback with its exact original payload and `sandboxChoice: "use"`; exit repeats the original `start` with top-level `sandboxChoice: "local"`. Preserve the original goal, risk, work type and requirements. A disabled account continues through its configured local workflow; unavailable preferences stop entry explicitly. Reuse a prior explicit choice while resuming this task. Silence never authorizes cloud consumption.
|
|
29
|
-
|
|
30
|
-
For an explicit cloud planning request without an existing start, `cloud-task` accepts `{"goal":"<actual goal>","ideTaskId":"<current IDE task ID, when available>"}` on stdin and returns the same choice. Do not start both routes for one task.
|
|
31
|
-
|
|
32
|
-
With `sandboxChoice: "use"` (or the protocol callback's `answer: "use"`), immediately display the returned acceptance message, for example **云端任务 08921 · 已进入**. Use the returned `taskNumber` verbatim: it matches the homepage sandbox tab and notification. Retain the UUID `taskId` separately for API queries; never display the IDE chat ID or invent a number instead. Then run the returned `nextAction`, `cloud-watch`. It subscribes to that account's authoritative SSE stream, returns newline-delimited `entrorove.ide-event/1.0` events, then one `entrorove.cloud-watch/1.0` result. **Mirror each new event's public `message` and optional `detail` into visible IDE progress/commentary.** Deduplicate by task ID and event ID, including the acceptance message repeated in the stream or final result. The same rule applies to normal invocation `ideMessages` and notice events. A JSON field or collapsed command log does not satisfy this display requirement. Show `智能执行中,请勿关闭!` and the selected promotion on separate lines; preserve the promotion's actual HTTPS link. Use only the server's selected promotion; do not insert a local test advertisement.
|
|
33
|
-
|
|
34
|
-
Display the actual entering, allocation, thinking, public output and exit events as they arrive. Do not generate model reasoning, invent intermediate events or replace `reported` with verified completion. The public model summary is the planning output available to show. `云端沙箱输出完毕` means the current planning response has arrived; inspect its real task/verification status before dependent execution. Exit here closes the progress subscription and does not cancel the persisted task.
|
|
35
|
-
|
|
36
|
-
When a bounded watch returns `nextAction`, continue it with the returned `afterId`; reconnect only with GET and that cursor. Never repeat cloud-task POST to recover progress. For an available planning result, query `status <feedback.requestId>` to obtain the original accepted flow and required next step, then continue that flow. Do not create a second `start` for the same cloud goal. If the task is still running but no events arrive, say so and keep reading its real status. Missing credentials, blocked entitlement, expiry and stream errors must be visible.
|
|
37
|
-
|
|
38
|
-
Set `ENTROROVE_IDE` to the actual host name (for example `Codex`, `Cursor` or `Claude Code`) when host detection is unavailable. It carries only the IDE label; credentials remain in the restricted store. Use the latest official package with `--prefer-online` for new invocations, and reread the managed `SKILL.md` after installation reports an update. Recovering an uncertain request remains a read-only query of its original ID.
|
|
39
|
-
|
|
40
|
-
Send JSON on standard input to `npx @entrorove/skill invoke`. Before every execution call, discover `operation: "capabilities"` with `{}` and validate input against the returned operation schema. The CLI performs remote discovery automatically; local adapters discover the installed contract before execution. Discovery failure stops execution. Adapters that expose the four-step task route can call `task-describe`, `message-route`, `message-accept` and `task-resume` in order; `start` remains the one-call workflow equivalent. Then start with `operation: "start"` and an `input.task` containing the goal, work type, risk, difficulty and observed scope facts. Work types are `implementation`, `documentation`, `calculation`, `merge`, `review`, `decision` and `diagnosis`. Assess facts from the real task and repository; do not invent certainty. entrorove chooses the workflow. A small task may return `decision: "direct"`, meaning the IDE should do the work without another service call. The public envelope is `entrorove.skill.request/2.0`; `requestId` is the SHA-256 digest of `operation + canonical(input)`. Version 1.0 remains accepted for older callers.
|
|
41
|
-
|
|
42
|
-
The server's ordinary `start` operation creates a durable skill flow and counts a skill invocation. The IDE CLI routes new starts through the account's preference and explicit task choice described above. A real sandbox is created only by `/api/cloud-task`, which returns both `taskId` and `taskNumber` and counts sandbox usage separately. `local` changes only this task's route. Disabled entitlement or missing model prerequisites stop cloud dispatch; a `needs-input`, `blocked` or `failed` result must never be described as sandbox entry. Do not send a second ordinary `start` after cloud acceptance; continue the original bound flow returned by its watch/status.
|
|
43
|
-
|
|
44
|
-
After dispatch, use `cloud-watch` for live IDE progress and `cloud-status` for a read-only snapshot with `input.taskId`. Both are CLI-only routes, also accepted by `invoke`; they do not pass through `/api/skill/invoke`. Status includes public title/summary, actual model usage and the stored automatic evaluation when available. A missing task is explicit and never treated as completed. The IDE and website consume the same account-bound event stream.
|
|
45
|
-
|
|
46
|
-
### Per-task cloud sandbox choice
|
|
47
|
-
|
|
48
|
-
When the host exposes an enabled cloud-sandbox preference and a new task is about to dispatch a cloud model, ask once whether this task should use the cloud sandbox. This is a low-risk routing preference, separate from agreement acceptance and the medium/high-risk confirmations below. Offer `use for this task` and `continue locally`; if the user gives no answer, continue locally. Cloud submission requires an explicit choice or the user’s existing authorization for this task; silence never authorizes cloud consumption. An explicit opt-out applies only to the current task and must not change the account-wide sandbox preference. Do not ask again while continuing or resuming the same task. If the host cannot preflight the account preference, show the choice only as a routing decision and let the server's authoritative `/api/cloud-task` check return a clear `blocked` prerequisite; never claim that a task started after a blocked response. This choice never bypasses the normal task schema, mutation authority, evidence checks, or risk confirmation.
|
|
49
|
-
|
|
50
|
-
```json
|
|
51
|
-
{"operation":"start","input":{"task":{"goal":"Update the checkout flow and verify it","workType":"implementation","risk":"medium","difficulty":"medium","crossModule":true,"parallel":false,"unclear":false,"architectureContract":false}}}
|
|
52
|
-
```
|
|
53
|
-
|
|
54
|
-
For `workType: "merge"`, include `baselineRef` with the concrete branch, tag, commit, or review baseline used for comparison. The API rejects a merge plan without it, and the baseline must remain unchanged through verification. For `workType: "decision"`, include the structured `interaction`; elevated-risk decisions also require `riskDescription`.
|
|
55
|
-
|
|
56
|
-
The v2 capability map is recorded in [`CAPABILITY-MAP.md`](CAPABILITY-MAP.md). It maps every legacy domain and operation to its v2 equivalent, narrower semantics, or an explicitly documented uncovered area; adapters must not silently substitute an uncovered operation.
|
|
57
|
-
|
|
58
|
-
For an explicit domain operation, use `npx @entrorove/skill native <domain> <operation>` with its input object on stdin. The supported domains are `aimlock`, `blueprint`, `calctool`, `swarm`, `validator`, `mergeguard`, `archguard` and `confirm-protocol`. This public adapter discovers that domain's actual server schema, validates the input, invokes the registered operation once, and verifies any required automatic feedback. Discovery, help and status observations follow the server's published feedback contract. A failed gate or unknown outcome must never be replaced with another executor or reported as local success; fix the original cause and recover the original request through its read-only status.
|
|
59
|
-
|
|
60
|
-
Aimlock exposes `brain-plan`, `brain-check`, `brain-validate` and `brain-status`. Create a plan with the actual goal, scope `contract`, `requirements` and ordered `steps`; retain its returned `requestId` and `plan.digest`. Subsequent operations take only that original `planRequestId` (plus `paths` for `brain-check`); the server loads the authenticated account's stored plan. Never submit a reconstructed plan or another account's request. Planning validation checks scope, requirements and dependencies; it grants no mutation authority and never certifies business delivery.
|
|
61
|
-
|
|
62
|
-
For a returned `flowId`, continue with `{"operation":"continue","input":{"flowId":"<returned ID>","operation":"<next operation>","payload":{}}}`. Fill `payload` with the next operation's required input. Keep the same task and evidence in the IDE. For later work, `input.task.phase` may be `plan`, `coordinate`, `architecture`, `verify`, `merge` or `decision`; it remains the same skill entry point. Never treat an unknown request outcome as permission to retry a paid or mutating action; query the original request ID when the workflow supports it.
|
|
63
|
-
|
|
64
|
-
The v2 progress sequence is durable and ordered: the first runtime step reports `intake`, then the applicability `gate` is recorded and verified, then the selected contract or plan steps run. Every step can be `pending`, `running`, `reported`, `verified`, `blocked` or `failed`; only a completed verdict with trusted evidence is green.
|
|
65
|
-
|
|
66
|
-
When intake returns `workflow-gate`, connect the current repository before invoking that gate: run `npx @entrorove/skill scope-connect <absolute repositoryRoot>` with JSON `{"flowId":"<original flowId>","paths":["<existing source file>"]}` on stdin. Use the concrete existing source files in the task's scope; new files belong in the later plan's declared artifacts. The adapter enrolls an OS-private Ed25519 scope signer for this accepted account and task, answers a server challenge, copies and verifies real source files, and submits the signed facts. It sends hashes and scope metadata rather than source contents or the private key. Enrollment grants scope inspection only; execution evidence and write passes retain their separate authority checks. An operator-configured signer cannot be replaced. After a successful connection, use the returned `nextInput` for `continue`, or explicitly send `payload: {"targetFiles":["<same existing source file>"]}` to the original `workflow-gate`. The connector uses `paths`; the gate uses `targetFiles`. Refresh an expired snapshot by reconnecting the same flow and path set. Show an explicit blocked result; query the original request ID after an unknown transport outcome before considering another attempt.
|
|
67
|
-
|
|
68
|
-
Scope inspection resolves aliases from actual `tsconfig.json` or `jsconfig.json`, including relative `extends`. For plugin source compiled by a host project whose config is outside the source's ancestors, include `importContexts: [{"sourcePrefix":"<plugin source directory>","configPath":"<actual host tsconfig.json>"}]` in `scope-connect` input. Inspect the real build configuration first; never invent an alias or mark an unresolved import as external. These context paths remain inside the repository, their hashes enter the signed facts, and the local task binding freezes them.
|
|
69
|
-
|
|
70
|
-
Computed runtime imports remain explicitly unresolved with their actual source paths and hashes. A member's scope-only signer may submit these observations to enter restricted planning; the cloud returns `planningOnly: true` and `requires-complete-import-graph-before-mutation`. Do not treat this as full dependency verification, execution permission, or business completion. Resolve the dynamic dependency contract and obtain complete verified facts before mutation; never set `complete` manually or replace the original signer or paths to bypass the restriction.
|
|
71
|
-
|
|
72
|
-
For a decision, include `input.task.interaction` with `type` (`confirm`, `choice`, `multi` or `input`), a `question`, `options` (two or more with unique `id` and `label`, or an empty array for input), and a `callback` containing its `operation` and `payload`. Medium- and high-risk decisions also need a `riskDescription`. The decision waits for an explicit answer; it never chooses a default on timeout.
|
|
73
|
-
|
|
74
|
-
Use `npx @entrorove/skill status <requestId>` after a connection loss. It performs a read-only GET lookup and never resends a POST. Use `npx @entrorove/skill flows` to list recoverable flow steps. A v2 flow has its own `flowId` and progresses through `pending`, `running`, `reported`, `verified`, `blocked` or `failed`; a reported result is not a verified result.
|
|
75
|
-
|
|
76
|
-
The local execution layer is available through `npx @entrorove/skill local <operation> [repositoryRoot]` with a JSON object on standard input. `local capabilities` lists the complete contract, operation groups and `requiresPass` metadata. `local capabilities <group>` filters that same contract. Operations include `snapshot-plan`, `snapshot-verify`, `mutate-gate`, `gate-issue`, `gate-verify`, `guarded-write`, `budget-init`, `budget-context`, `budget-read`, `budget-status`, `budget-extend`, budget renewal confirmation, `peer-coordinate`, `spawn-bind`, `peer-complete`, `lease-verify`, `probe`, `reassess`, execution ledger and virtual branch records, `chain-init`, `chain-resume`, `chain-status`, `chain-answer`, `evidence-sign`, `evidence-verify`, `merge-verified`, `rollback`, `formula-evaluate`, `formula-graph`, `formula-final-gate`, `run-approved-plan` and `final-gate`. State is kept only under `~/.entrorove/`; snapshots never create Git branches or worktrees. Guarded writes require a short-lived Ed25519 pass bound to the flow, step, snapshot digest and path set. Local evidence uses `entrorove.test-evidence/2.0`; unsigned local evidence remains incomplete and verified delivery requires a trusted receipt. Approved plan execution requires a frozen plan, matching approval and unchanged files; without a configured runner signer it reports local evidence as incomplete.
|
|
77
|
-
|
|
78
|
-
Local CLI failures use the machine-readable `entrorove.local-error/1.0` envelope `{schemaVersion,status,code,disposition,message}` on stderr. `status` is `failed` for invalid input or computation errors and `blocked` for missing mutation, lease, snapshot or handoff authority. Formula `add` and `mul` require at least one argument; `div`, `safeDivide` and `percentOf` reject a zero denominator with `DIV_ZERO`. The formula engine declares `round` as half-away-from-zero with two decimal places by default; an engine may declare another `decimalPlaces` value from 0 through 28 in its `roundingPolicy`.
|
|
79
|
-
|
|
80
|
-
### Read-only peer status
|
|
81
|
-
|
|
82
|
-
`local peer-status` observes the original signed worker grant, task and lease, or the registered coordination task/agent/chain/intent binding. It reports only that worker's active, waiting or expired state, own blocked/ready paths and own checkpoint requests. Queries do not issue leases, change ownership, write a coordination journal or grant permission to write. Use `local capabilities` for the exact supported input variants.
|
|
83
|
-
|
|
84
|
-
### Optional task notifications
|
|
85
|
-
|
|
86
|
-
System notifications are disabled until this account explicitly enables them. `npx @entrorove/skill notifications configure` accepts only `{"enabled":true}` or `{"enabled":false}` on stdin; `notifications status` observes the account's setting and `notifications test` submits a generic test only when enabled. macOS and Linux use their existing notification service. Cloud notifications show the same `taskNumber` as the website: one entry and one ending, including a specific model-balance warning. Intermediate steps, promotion, keep-alive and repeated feedback do not repeat notifications. A rejected OS submission is not marked as sent and remains retryable. Settings use the same home and account as the invocation; changing the credential disables the previous account's setting. OS acceptance does not prove that a notification was visibly displayed.
|
|
87
|
-
|
|
88
|
-
The website's signed-in bell control enables encrypted Web Push for the current account and device. Desktop browsers and supported phones use this same push protocol; iPhone requires a Home Screen web app. Ask permission only through the user's enable action. Logout clears the browser binding and subscription. Messages contain only generic task status, with no prompts, credentials, model output or promotion. Delivery retries keep the original event and device binding; expired endpoints and temporary tasks are cleaned up automatically. Never describe an unsupported platform or failed delivery as a successful notification.
|
|
89
|
-
|
|
90
|
-
### Automatic invocation evaluation and optional user reviews
|
|
91
|
-
|
|
92
|
-
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.
|
|
93
|
-
|
|
94
|
-
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.
|
|
95
|
-
|
|
96
|
-
When the user gives an actual evaluation after using the skill, offer to publish that feedback. Only after they explicitly agree to public display under the current notice, send their unchanged words, IDE name and 1–5 rating as JSON on standard input to `npx @entrorove/skill review`, including `invocationRequestId` from their actual successful call, `publicConsent: true` and `noticeVersion: "2026-10-07.1"`. The same account must own that successful call within the last 30 days; a recorded usage event, failed call or unknown result does not qualify. Three public reviews per account per day share one server quota across API replicas. Public output exposes only IDE, rating, original text and time, never account or invocation identity. Never invent, rewrite or infer a review from task completion. The website reads accepted reviews directly from entrorove's independent database.
|
|
97
|
-
|
|
98
|
-
Feedback command example (replace the request ID with the original successful invocation ID, and use only the user’s actual words after explicit public consent):
|
|
99
|
-
|
|
100
|
-
```json
|
|
101
|
-
{"invocationRequestId":"<original successful request ID>","ide":"Codex","rating":5,"comment":"<unchanged user words>","publicConsent":true,"noticeVersion":"2026-10-07.1"}
|
|
102
|
-
```
|
|
103
|
-
|
|
104
|
-
Ordinary Windows scope inspection resolves an absolute Git for Windows `git.exe` from its installation or absolute PATH directories, including paths containing spaces. It never invokes `/usr/bin/git` on Windows, a shell wrapper or a Git executable inside the inspected repository. Missing Git gives `ENTROROVE_GIT_UNAVAILABLE` and requires installing Git for Windows before reconnecting the original scope.
|
|
105
|
-
|
|
106
|
-
The fixed Git byte-metering adapter ships hash-pinned precompiled libraries for Darwin and glibc Linux on arm64/x64. It extracts the selected library on first use; it never invokes a C compiler on the user machine. Darwin requires Apple’s trusted Git (Xcode or Command Line Tools), xcrun and codesign; Linux requires the trusted `/usr/bin/git` and glibc. Native comparisons with enforced source-read budgets remain restricted to these platforms. An unsupported native budget adapter returns `ENTROROVE_GIT_READER_UNSUPPORTED`; do not bypass its budget or claim an ordinary Windows inspection verifies that separate capability.
|
|
35
|
+
Read [CAPABILITY-MAP.md](CAPABILITY-MAP.md) when an explicit capability needs mapping. Read the relevant sections of [IDE-EXECUTION.md](IDE-EXECUTION.md) for confirmed notifications, cross-platform execution, original runner signatures and recovery contracts. Preserve existing authorization; do not ask the same permission again.
|
package/cli.mjs
CHANGED
|
@@ -18,18 +18,17 @@ import { buildReview, submitSkillFeedback, feedbackNoticeVersion } from './revie
|
|
|
18
18
|
import { queryCloudTask, runCloudTask as dispatchCloudTask } from './cloud-task-client.mjs';
|
|
19
19
|
import { watchCloudTask } from './cloud-watch-client.mjs';
|
|
20
20
|
import { queryAutomaticFeedback } from './automatic-feedback-client.mjs';
|
|
21
|
+
import { installIdeHooks } from './ide-install.mjs';
|
|
22
|
+
import { assertIdeExecution } from './ide-session.mjs';
|
|
21
23
|
const markerName = '.entrorove-managed.json';
|
|
22
|
-
const installFiles = ['SKILL.md', 'CAPABILITY-MAP.md', 'AGREEMENT.md', 'manifest.json'];
|
|
24
|
+
const installFiles = ['SKILL.md', 'CAPABILITY-MAP.md', 'AGREEMENT.md', 'manifest.json', 'IDE-EXECUTION.md', 'REUSE-DISCIPLINE.md'];
|
|
23
25
|
const markerSchema = 'entrorove.managed-install/1.0';
|
|
24
26
|
const agreementSchema = 'entrorove.agreement-acceptance/1.0';
|
|
25
27
|
const installLockWaitMs = 10_000;
|
|
26
28
|
const installLockStaleMs = 120_000;
|
|
27
29
|
export const agreementVersion = feedbackNoticeVersion;
|
|
28
30
|
|
|
29
|
-
function sha256(content) {
|
|
30
|
-
return createHash('sha256').update(content).digest('hex');
|
|
31
|
-
}
|
|
32
|
-
|
|
31
|
+
function sha256(content) { return createHash('sha256').update(content).digest('hex'); }
|
|
33
32
|
|
|
34
33
|
async function readJson(file) {
|
|
35
34
|
let value;
|
|
@@ -300,7 +299,8 @@ export async function install({ home = os.homedir(), cwd = process.cwd() } = {})
|
|
|
300
299
|
return withInstallLock(parent, async () => {
|
|
301
300
|
const updated = await updateGlobalInstall(target, bundle);
|
|
302
301
|
const removed = await cleanProjectDuplicates(target, cwd);
|
|
303
|
-
|
|
302
|
+
const ide = await installIdeHooks({ home, version: bundle.manifest.version });
|
|
303
|
+
return { version: bundle.manifest.version, updated, removed, agreementStale: stale, ide };
|
|
304
304
|
});
|
|
305
305
|
}
|
|
306
306
|
|
|
@@ -313,6 +313,8 @@ async function stdinJson() {
|
|
|
313
313
|
let value;
|
|
314
314
|
try { value = JSON.parse(raw); } catch { throw new Error('Input must be valid JSON'); }
|
|
315
315
|
if (!value || typeof value !== 'object' || Array.isArray(value)) throw new Error('Input must be a JSON object');
|
|
316
|
+
const args = process.argv.slice(2);
|
|
317
|
+
if (!['configure','agreement','review'].includes(args[0])) await assertIdeExecution(args, value);
|
|
316
318
|
return value;
|
|
317
319
|
}
|
|
318
320
|
|
|
@@ -489,8 +491,10 @@ async function main() {
|
|
|
489
491
|
}
|
|
490
492
|
}
|
|
491
493
|
if (process.argv[1] && realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url))) {
|
|
494
|
+
const { captureIdeResults } = await import('./ide-results.mjs');
|
|
495
|
+
const finish = captureIdeResults();
|
|
492
496
|
main().catch((error) => {
|
|
493
497
|
process.stderr.write(`${error instanceof SyntaxError ? 'Invalid JSON data' : error.message}\n`);
|
|
494
498
|
process.exitCode = 1;
|
|
495
|
-
});
|
|
499
|
+
}).finally(finish).catch(() => { process.stderr.write('Entrorove IDE completion could not be saved; recover the original request.\n'); process.exitCode = 1; });
|
|
496
500
|
}
|
package/cloud-task-client.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
2
|
import { appendInvocation } from './local-invocations.mjs';
|
|
3
3
|
import { parseTransportResponse, requestTransport, trustedOrigin } from './remote-transport.mjs';
|
|
4
|
-
import { displayIdeEvent, ideClientHeaders } from './ide-presentation.mjs';
|
|
4
|
+
import { displayIdeEvent, ideClientHeaders, ideTaskIdentity } from './ide-presentation.mjs';
|
|
5
5
|
import { verifyAutomaticFeedback } from './automatic-feedback-client.mjs';
|
|
6
6
|
import { sandboxTaskNumber } from './task-identity.mjs';
|
|
7
7
|
|
|
@@ -85,6 +85,8 @@ async function responseBody(response) {
|
|
|
85
85
|
|
|
86
86
|
export async function runCloudTask(input, dependencies) {
|
|
87
87
|
const task = validateInput(input);
|
|
88
|
+
const ideTaskId = ideTaskIdentity(task.ideTaskId);
|
|
89
|
+
if (ideTaskId) task.ideTaskId = ideTaskId;
|
|
88
90
|
validateDependencies(dependencies);
|
|
89
91
|
const id = requestId(task);
|
|
90
92
|
const choice = input.sandboxChoice ?? input.answer;
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import { literalCommand, sdkCommand, readCommand } from './ide-command.mjs';
|
|
3
|
+
|
|
4
|
+
export function inspectIdeCodeMode(code, runtime) {
|
|
5
|
+
if (typeof code !== 'string' || code.length > 1_000_000) return false;
|
|
6
|
+
const ts = createRequire(runtime.cli)('typescript');
|
|
7
|
+
const source = ts.createSourceFile('host-call.js', code, ts.ScriptTarget.Latest, true, ts.ScriptKind.JS);
|
|
8
|
+
if (source.parseDiagnostics.length) return false;
|
|
9
|
+
let allowed = true;
|
|
10
|
+
const literal = node => {
|
|
11
|
+
if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text;
|
|
12
|
+
if (ts.isNumericLiteral(node)) return Number(node.text);
|
|
13
|
+
if (node.kind === ts.SyntaxKind.TrueKeyword) return true;
|
|
14
|
+
if (node.kind === ts.SyntaxKind.FalseKeyword) return false;
|
|
15
|
+
if (node.kind === ts.SyntaxKind.NullKeyword) return null;
|
|
16
|
+
if (ts.isArrayLiteralExpression(node)) return node.elements.map(literal);
|
|
17
|
+
if (ts.isObjectLiteralExpression(node)) return Object.fromEntries(node.properties.map(property => {
|
|
18
|
+
if (!ts.isPropertyAssignment(property) || !(ts.isIdentifier(property.name) || ts.isStringLiteral(property.name))) throw new Error('Dynamic tool arguments');
|
|
19
|
+
return [property.name.text, literal(property.initializer)];
|
|
20
|
+
}));
|
|
21
|
+
throw new Error('Dynamic tool arguments');
|
|
22
|
+
};
|
|
23
|
+
const visit = node => {
|
|
24
|
+
if (ts.isImportDeclaration(node) || ts.isNewExpression(node) || ts.isElementAccessExpression(node) || ts.isFunctionExpression(node)) allowed = false;
|
|
25
|
+
if (ts.isCallExpression(node)) {
|
|
26
|
+
const name = node.expression.getText(source);
|
|
27
|
+
if (name === 'tools.exec_command') {
|
|
28
|
+
try {
|
|
29
|
+
const args = literal(node.arguments[0]), command = literalCommand(args.cmd ?? args.command);
|
|
30
|
+
if (!(readCommand(command) || sdkCommand(command, runtime))) allowed = false;
|
|
31
|
+
} catch { allowed = false; }
|
|
32
|
+
} else if (!['text','image','notify','Promise.all','Promise.allSettled'].includes(name)
|
|
33
|
+
&& !/^tools\.(?:view_image|web__run|list_mcp_resources|list_mcp_resource_templates|read_mcp_resource|clock__curr_time)$/u.test(name)) allowed = false;
|
|
34
|
+
}
|
|
35
|
+
ts.forEachChild(node, visit);
|
|
36
|
+
};
|
|
37
|
+
visit(source); return allowed;
|
|
38
|
+
}
|
package/ide-command.mjs
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
|
|
3
|
+
// Deliberately accepts a small literal shell grammar. Unknown commands are not
|
|
4
|
+
// classified as reads: the host must reject them or use the approved runner.
|
|
5
|
+
export function literalCommand(command) {
|
|
6
|
+
if (typeof command !== 'string' || command.length > 1_000_000) return null;
|
|
7
|
+
let header = command.trim(), input;
|
|
8
|
+
const here = header.match(/^([^\n]+?)\s+<<\s*'([A-Za-z][A-Za-z0-9_]*)'\r?\n([\s\S]*)$/u);
|
|
9
|
+
if (here) {
|
|
10
|
+
const ending = new RegExp(`\\r?\\n${here[2]}$`, 'u');
|
|
11
|
+
if (!ending.test(here[3])) return null;
|
|
12
|
+
try { input = JSON.parse(here[3].replace(ending, '')); } catch { return null; }
|
|
13
|
+
if (!input || typeof input !== 'object' || Array.isArray(input)) return null;
|
|
14
|
+
header = here[1];
|
|
15
|
+
}
|
|
16
|
+
if (/[\n\r\0`$<>;&|]/u.test(header)) return null;
|
|
17
|
+
const words = [], pattern = /\s*(?:'([^']*)'|"([^"\\]*)"|([^\s'"\\]+))/gu;
|
|
18
|
+
let match, end = 0;
|
|
19
|
+
while ((match = pattern.exec(header))) {
|
|
20
|
+
if (match.index !== end) return null;
|
|
21
|
+
words.push(match[1] ?? match[2] ?? match[3]); end = pattern.lastIndex;
|
|
22
|
+
}
|
|
23
|
+
if (end !== header.length || !words.length) return null;
|
|
24
|
+
return { words, ...(input ? { input } : {}) };
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function sdkCommand(parsed, runtime) {
|
|
28
|
+
if (!parsed) return null;
|
|
29
|
+
const words = [...parsed.words];
|
|
30
|
+
if (words[0]?.startsWith('ENTROROVE_IDE=')) {
|
|
31
|
+
if (words.shift() !== 'ENTROROVE_IDE=Codex') return null;
|
|
32
|
+
}
|
|
33
|
+
let args;
|
|
34
|
+
if ([runtime.node, 'node'].includes(words[0]) && words[1] === runtime.cli) args = words.slice(2);
|
|
35
|
+
else if (['npx', 'npx.cmd'].includes(path.basename(words[0]))) {
|
|
36
|
+
words.shift();
|
|
37
|
+
while (['--yes', '--prefer-online'].includes(words[0])) words.shift();
|
|
38
|
+
if (!['@entrorove/skill', '@entrorove/skill@latest', `@entrorove/skill@${runtime.version}`].includes(words.shift())) return null;
|
|
39
|
+
args = words;
|
|
40
|
+
} else return null;
|
|
41
|
+
const simple = new Set(['invoke', 'cloud-task', 'cloud-status', 'cloud-watch', 'agreement', 'configure']);
|
|
42
|
+
if (simple.has(args[0]) && args.length === 1 && parsed.input) return { args, input: parsed.input };
|
|
43
|
+
if (['status', 'feedback'].includes(args[0]) && /^[a-f0-9]{64}$/u.test(args[1] ?? '') && [2,3].includes(args.length)) return { args };
|
|
44
|
+
if (['flows', 'install'].includes(args[0]) && args.length === 1 && !parsed.input) return { args };
|
|
45
|
+
if (args[0] === 'local' && /^[a-z][a-z0-9-]+$/u.test(args[1] ?? '') && [2,3].includes(args.length) && parsed.input) return { args, input: parsed.input };
|
|
46
|
+
if (args[0] === 'scope-connect' && args.length === 2 && parsed.input) return { args, input: parsed.input };
|
|
47
|
+
if (args[0] === 'native' && args.length === 3 && parsed.input) return { args, input: parsed.input };
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
export function installerCommand(parsed) {
|
|
51
|
+
if (!parsed || parsed.input || !['npx', 'npx.cmd'].includes(parsed.words[0])) return null;
|
|
52
|
+
const words = [...parsed.words]; words.shift();
|
|
53
|
+
while (['--yes', '--prefer-online', '--registry=https://registry.npmjs.org'].includes(words[0])) words.shift();
|
|
54
|
+
if (words.length !== 2 || !/^@entrorove\/skill(?:@(?:latest|\d+\.\d+\.\d+))?$/u.test(words[0]) || words[1] !== 'install') return null;
|
|
55
|
+
return `npx --yes --prefer-online --registry=https://registry.npmjs.org ${words[0]} install`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function readCommand(parsed) {
|
|
59
|
+
if (!parsed || parsed.input) return false;
|
|
60
|
+
const [program, ...args] = parsed.words;
|
|
61
|
+
if (program.includes(path.sep)) return false;
|
|
62
|
+
if (program === 'pwd') return args.length === 0;
|
|
63
|
+
if (program === 'cat') return args.length > 0 && args.every(arg => !arg.startsWith('-') || arg === '--');
|
|
64
|
+
if (program === 'ls') return args.every(arg => !arg.startsWith('-') || /^-[alh1d]+$/u.test(arg) || arg === '--');
|
|
65
|
+
if (program === 'rg') return args.length > 0 && args.every(arg => !arg.startsWith('-')
|
|
66
|
+
|| /^-[nilwF0]+$/u.test(arg) || /^--(?:files|hidden|no-ignore|line-number|fixed-strings|glob|type|count|files-with-matches|files-without-match|color=never)$/u.test(arg) || arg === '--');
|
|
67
|
+
if (program === 'sed') return args.length === 3 && args[0] === '-n' && /^\d+(?:,\d+)?p$/u.test(args[1]) && !args[2].startsWith('-');
|
|
68
|
+
if (['head', 'tail'].includes(program)) return args.length === 3 && args[0] === '-n' && /^[1-9][0-9]{0,4}$/u.test(args[1]) && !args[2].startsWith('-');
|
|
69
|
+
return false;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function renderSdkCommand(call, runtime, sessionId) {
|
|
73
|
+
const quote = value => `'${String(value).replace(/'/gu, "'\\''")}'`;
|
|
74
|
+
const header = `ENTROROVE_IDE=Codex CODEX_THREAD_ID=${quote(sessionId)} ${[runtime.node, runtime.cli, ...call.args].map(quote).join(' ')}`;
|
|
75
|
+
return call.input ? `${header} <<'ENTROROVE_INPUT'\n${JSON.stringify(call.input)}\nENTROROVE_INPUT` : header;
|
|
76
|
+
}
|