@entrorove/skill 0.1.60 → 0.1.61
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/CHANGELOG.md +5 -0
- package/IDE-EXECUTION.md +7 -2
- package/SKILL.md +6 -5
- package/cli.mjs +13 -9
- package/ide-command.mjs +22 -6
- package/ide-hook.mjs +14 -21
- package/ide-install.mjs +7 -5
- package/ide-selection.mjs +31 -0
- package/ide-session.mjs +7 -2
- package/manifest.json +1 -1
- package/package.json +2 -1
- package/release-state.json +12 -11
- package/release.mjs +1 -1
- package/releases.json +6 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.61 — 2026-10-18
|
|
4
|
+
|
|
5
|
+
- 钩子改为可选:默认安装关闭钩子,IDE 可直接调用 SDK;只有明确选用技能的原会话与仓库启用拦截,普通查询、旧激活状态及无法归属的事件不再接管其他任务。保留账号、写入范围、签名和真实本地验收校验。
|
|
6
|
+
- Make hooks optional: default installs disable hooks and IDEs can call the SDK directly. Interception requires explicit selection of the original session and repository; discovery, legacy activation and unidentified events cannot govern unrelated work. Preserve account, mutation scope, signatures and actual local acceptance checks.
|
|
7
|
+
|
|
3
8
|
## 0.1.60 — 2026-10-17
|
|
4
9
|
|
|
5
10
|
- 修复范围补正误用独立交接的完整依赖校验,接收原账号签名器的真实受限扫描并保留未解析依赖、原审批与预算;新增当前 IDE 会话离线 exit,识别明确停用决定并保持退出状态,不再要求重建流程。
|
package/IDE-EXECUTION.md
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
-
Install or update the managed copy with `npx @entrorove/skill install`.
|
|
1
|
+
Install or update the managed copy with `npx @entrorove/skill install --host codex`. The default installs the skill with hooks disabled; SDK operations work directly in Codex, Claude Code or other IDEs without a hook approval. An explicit default reinstall removes only the recorded Codex hooks. It leaves Claude Code settings and skill copies alone, preserves hand-edited files and cannot downgrade a newer managed skill. Ordinary commands never install the skill or restore removed callbacks.
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Hooks are optional: use `install --host codex --hooks` only when the user requests interception. Registration alone is passive. An explicit prompt (`使用 entrorove` or `$entrorove`) selects that exact IDE session and physical repository. Discovery, status, SDK calls and legacy active bits never select it. Unselected callbacks create no session/queue state and cannot deny native tools or block Stop. `install --host codex --no-hooks` returns to direct SDK mode. A selected callback adds `ENTROROVE_HOOK_MODE=required` only to its rewritten SDK invocation; the CLI validates the original exact approval and account for that call. Do not set this internal marker in ordinary direct SDK commands.
|
|
4
|
+
|
|
5
|
+
Without hooks, explicitly call the returned SDK operations, preserve request IDs and signed receipts, and recover unknown outcomes through status. Account authentication, agreement, original scope, mutation passes and real test/acceptance checks are unchanged. SDK receipts cover only SDK operations; native IDE edits are not automatically intercepted, recorded or certified. Automatic prompt queue capture, callback synchronization and Stop continuation require an enabled, explicitly selected hook. Cloud sandbox preference is independent of hook mode.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
Host hook events, including multimodal `PostToolUse` screenshot results, accept at most 32 MiB (33,554,432 UTF-8 bytes). The complete bounded event is decoded once and follows the original session, tool-call and signature checks; image results do not grant permissions or erase a pending call. Oversized events return `ENTROROVE_IDE_INPUT_TOO_LARGE`; invalid UTF-8 or JSON objects return `ENTROROVE_IDE_INPUT_INVALID_JSON`. These fixed diagnostics do not include the event contents. Malformed transport cannot identify a selected session, so it returns a nonblocking diagnostic rather than stopping unrelated work; errors inside a positively identified selected session still reject the affected call. Private IDE state JSON files retain their separate 1,000,000-byte limit. A hook error after a tool action does not prove the action was unexecuted: inspect the original result or status before considering another attempt.
|
|
4
9
|
|
|
5
10
|
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.
|
|
6
11
|
|
package/SKILL.md
CHANGED
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: entrorove
|
|
3
|
-
description: Execute
|
|
3
|
+
description: Execute a task selected for Entrorove through explicit SDK operations, preserving its scope, approvals and verifiable results. Hooks are optional; unrelated IDE work remains outside its governance.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# entrorove · 熵巡
|
|
7
7
|
|
|
8
|
-
Version: 0.1.
|
|
8
|
+
Version: 0.1.61.
|
|
9
9
|
|
|
10
|
-
Entrorove applies to the
|
|
10
|
+
Entrorove applies only to the task for which it is selected; reading these instructions, discovering capabilities or installing the package never selects or governs another task. Hooks are optional. Reading this document or calling an entry once does not execute the task. On every later turn, including after compaction, continue the original task and its required next operation before dependent work. Keep the original goal, scope, account, flow, cloud task and failure records. Never describe planning, a reported step or model output as verified delivery.
|
|
11
11
|
|
|
12
12
|
## Required execution
|
|
13
13
|
|
|
14
|
-
1. Install `npx --yes --prefer-online @entrorove/skill@latest install --host codex`
|
|
14
|
+
1. Install `npx --yes --prefer-online @entrorove/skill@latest install --host codex` only when the user chooses to install this skill. The default installs the skill with hooks disabled and removes its recorded Codex hooks on upgrade, preserving other host settings. SDK calls work directly in an IDE without a hook callback or supported hook adapter; retain the actual host identity. Missing credentials, failed discovery and the SDK/API's scope, approval and evidence checks still return explicit failures.
|
|
15
|
+
Only when the user requests automatic interception, use `install --host codex --hooks`. The hook stays passive until this session receives an explicit selection such as `使用 entrorove` or `$entrorove`. SDK discovery, installation, another session, another repository and old automatic activation records cannot select it. In a selected session, the hook binds each rewritten SDK call to its exact live approval. `install --host codex --no-hooks` disables only the recorded Codex hooks; ordinary calls never reinstall removed hooks. A disabled hook cannot be described as enforced. Do not ask the user to type a nonexistent `/hooks` command.
|
|
15
16
|
`entrorove unlock` is the break-glass path: run the installed CLI directly in the affected IDE terminal. It writes a short-lived lease for that IDE session only, without a hook callback, network request, credential read, agreement check or protocol lookup. The current session ID must be available from the host environment or `ENTROROVE_SESSION`. The lease permits `flow-cancel` and `flow-abandon` recovery, never project writes or another session's calls. A successful `flow-abandon` clears that session's old binding locally even without a hook callback and preserves its queued requests.
|
|
16
17
|
To remove this skill and its host hooks, run `entrorove uninstall` directly. It works offline and preserves unrelated host settings, credentials and task records. If a managed file was edited, it reports the preserved path instead of deleting it.
|
|
17
18
|
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.
|
|
@@ -26,7 +27,7 @@ Entrorove applies to the whole task once selected. Reading this document or call
|
|
|
26
27
|
8. Read [DELIVERY-BOUNDARIES.md](DELIVERY-BOUNDARIES.md) before claiming a delivered stage or showing consumption. A delivered stage requires a clean boundary and uses `delivered-stage-N`. Blocked or unknown work can wait with recovery data intact; it is not a delivered stage. Display consumption only with a measured baseline.
|
|
27
28
|
9. For independent verified completion, submit actual independent execution evidence and run server verification and verdict. For a signed member-local plan, finish all original local steps and requirement checkpoints, then call the returned `workflow-verdict`; only its signed final `localAcceptance` means local acceptance is complete. Describe it as local execution and tests accepted, with independent validation not performed. Never invoke formal V, merge, Swarm or handoff to relabel it. Display the confirmed evaluation acknowledgement and preserve `receiptId`, `requestId`, execution generation and evaluation digest. “已回传” requires `acknowledgement.stored: true`. Missing or failed feedback remains visible. Active, waiting and unknown tasks retain recovery data.
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
When explicitly enabled and selected, the Codex guard preserves this binding over subsequent prompts and compaction and denies unsupported native mutations before execution. Without hooks, explicitly execute the returned SDK operations and retain their real request IDs and receipts; automatic prompt queue capture, callback recovery and Stop interception are unavailable. SDK evidence covers only operations performed through the SDK, not arbitrary IDE edits. 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. For that explicit decision, run `entrorove exit` in the affected IDE session. It works offline without a credential, agreement or hook callback, stops governance for that session and preserves its original flow, failed requests and queued work. It does not cancel the business goal, resume another flow or grant an Entrorove mutation pass. Do not substitute `flow-abandon` for user exit: abandonment releases a flow binding but leaves the skill selected.
|
|
30
31
|
|
|
31
32
|
After the same real blocked result occurs twice, diagnose it and use its supported recovery path. Do not send a third identical execution call. Read-only status and checkpoint acknowledgements do not count as execution progress. A blocked task may wait with its original flow, queue and recovery data intact; Stop must not force repeated automatic continuation of the same blocked turn.
|
|
32
33
|
|
package/cli.mjs
CHANGED
|
@@ -22,6 +22,7 @@ import { cleanManagedDuplicates } from './install-cleanup.mjs';
|
|
|
22
22
|
import { assertIdeExecution, ideGuardBinding, settleBreakGlassSession } from './ide-session.mjs';
|
|
23
23
|
import { writeBreakGlass } from './break-glass.mjs';
|
|
24
24
|
import { exitIdeSession } from './ide-exit.mjs';
|
|
25
|
+
import { installOptions } from './ide-command.mjs';
|
|
25
26
|
const markerName = '.entrorove-managed.json';
|
|
26
27
|
const installFiles = ['SKILL.md', 'CAPABILITY-MAP.md', 'AGREEMENT.md', 'manifest.json', 'IDE-EXECUTION.md', 'REUSE-DISCIPLINE.md', 'DELIVERY-BOUNDARIES.md'];
|
|
27
28
|
const markerSchema = 'entrorove.managed-install/1.0';
|
|
@@ -247,8 +248,8 @@ async function updateGlobalInstall(target, bundle) {
|
|
|
247
248
|
return true;
|
|
248
249
|
}
|
|
249
250
|
|
|
250
|
-
export async function install({ home = os.homedir(), cwd = process.cwd(), explicit = false, hostId } = {}) {
|
|
251
|
-
const selected =
|
|
251
|
+
export async function install({ home = os.homedir(), cwd = process.cwd(), explicit = false, hostId, hooks = false } = {}) {
|
|
252
|
+
const selected = ideAdapters.find(adapter => adapter.id === (hostId ?? 'codex'));
|
|
252
253
|
if (hostId !== undefined && hostId !== 'codex') throw new Error('Install host must be codex');
|
|
253
254
|
const target = globalInstallPath(home);
|
|
254
255
|
if (!explicit && !(await managedState(target))) return { installed: false, updated: false };
|
|
@@ -256,16 +257,19 @@ export async function install({ home = os.homedir(), cwd = process.cwd(), explic
|
|
|
256
257
|
await fs.mkdir(parent, { recursive: true, mode: 0o700 });
|
|
257
258
|
return withInstallLock(parent, async () => {
|
|
258
259
|
const active = explicit ? null : await activeIdeAdapters({ home });
|
|
259
|
-
if (!explicit &&
|
|
260
|
+
if (!explicit && !(await managedState(target))) return { installed: false, updated: false };
|
|
260
261
|
const bundle = await sourceBundle();
|
|
261
262
|
const stale = await agreementStale(home);
|
|
262
263
|
const updated = await updateGlobalInstall(target, bundle);
|
|
263
264
|
const { removed, preserved } = await cleanManagedDuplicates({
|
|
264
265
|
target, cwd, home, isManaged: managedState, includeProject: explicit,
|
|
265
|
-
hostIds:
|
|
266
|
+
hostIds: explicit ? [selected.id] : active.map(adapter => adapter.id),
|
|
266
267
|
});
|
|
267
|
-
const
|
|
268
|
-
|
|
268
|
+
const targets = explicit ? hooks ? [selected] : [] : active;
|
|
269
|
+
const disabled = explicit && !hooks ? await uninstallIdeHooks({ home, adapters: [selected] }) : null;
|
|
270
|
+
const ide = targets.length ? await installIdeHooks({ home, version: bundle.manifest.version, adapters: targets })
|
|
271
|
+
: { host: selected.host, configured: false, enforcement: 'disabled', mode: 'explicit-sdk',
|
|
272
|
+
...(disabled ?? {}), message: '技能已安装;钩子关闭,SDK 可直接调用。' };
|
|
269
273
|
return { version: bundle.manifest.version, updated, removed, preserved, agreementStale: stale, ide };
|
|
270
274
|
});
|
|
271
275
|
}
|
|
@@ -436,8 +440,8 @@ async function main() {
|
|
|
436
440
|
const result = await uninstall();
|
|
437
441
|
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
438
442
|
if (!result.uninstalled) process.exitCode = 2;
|
|
439
|
-
} else if (command === 'install' && (
|
|
440
|
-
process.stdout.write(JSON.stringify(await install({ explicit: true,
|
|
443
|
+
} else if (command === 'install' && installOptions([command, ...args])) {
|
|
444
|
+
process.stdout.write(JSON.stringify(await install({ explicit: true, ...installOptions([command, ...args]) })) + '\n');
|
|
441
445
|
} else if (command === 'configure' && args.length === 0) {
|
|
442
446
|
const data = await stdinJson();
|
|
443
447
|
if (Object.keys(data).length !== 1 || typeof data.token !== 'string') throw new Error('Expected {"token":"..."} on stdin');
|
|
@@ -480,7 +484,7 @@ async function main() {
|
|
|
480
484
|
} else if (command === 'local') {
|
|
481
485
|
await runLocal(args);
|
|
482
486
|
} else {
|
|
483
|
-
throw new Error('Usage: entrorove exit | unlock | uninstall | install [--host codex] | configure | agreement | invoke | queue | native <domain> <operation> | notifications configure|status|test | scope-connect <repositoryRoot> | scope-amend <repositoryRoot> | mutation-connect <repositoryRoot> | mutation-settle <repositoryRoot> | workflow-observe-step <repositoryRoot> | host-message [adapterModulePath] | cloud-task | cloud-watch | cloud-status | feedback <requestId> [generation] | status <requestId> | flows | usage [flowId] | billing | recurring list|claim|finish|runs | review | local (JSON on stdin)');
|
|
487
|
+
throw new Error('Usage: entrorove exit | unlock | uninstall | install [--host codex] [--hooks|--no-hooks] | configure | agreement | invoke | queue | native <domain> <operation> | notifications configure|status|test | scope-connect <repositoryRoot> | scope-amend <repositoryRoot> | mutation-connect <repositoryRoot> | mutation-settle <repositoryRoot> | workflow-observe-step <repositoryRoot> | host-message [adapterModulePath] | cloud-task | cloud-watch | cloud-status | feedback <requestId> [generation] | status <requestId> | flows | usage [flowId] | billing | recurring list|claim|finish|runs | review | local (JSON on stdin)');
|
|
484
488
|
}
|
|
485
489
|
}
|
|
486
490
|
if (process.argv[1] && realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url))) { const { captureIdeResults } = await import('./ide-results.mjs');
|
package/ide-command.mjs
CHANGED
|
@@ -55,6 +55,8 @@ function sdkWords(parsed) {
|
|
|
55
55
|
seen.add(key);
|
|
56
56
|
if (key === 'ENTROROVE_IDE') {
|
|
57
57
|
if (!/^[\p{L}\p{N} .+_-]{2,48}$/u.test(value)) return null;
|
|
58
|
+
} else if (key === 'ENTROROVE_HOOK_MODE') {
|
|
59
|
+
if (value !== 'required') return null;
|
|
58
60
|
} else if (!['ENTROROVE_SESSION', 'CODEX_THREAD_ID', 'CLAUDE_SESSION_ID'].includes(key)
|
|
59
61
|
|| !/^[A-Za-z0-9_-]{1,200}$/u.test(value)) return null;
|
|
60
62
|
}
|
|
@@ -81,8 +83,8 @@ export function sdkCommand(parsed, runtime) {
|
|
|
81
83
|
if (['status', 'feedback'].includes(args[0]) && /^[a-f0-9]{64}$/u.test(args[1] ?? '') && [2,3].includes(args.length)) return { args };
|
|
82
84
|
if (args[0] === 'flows' && args.length === 1 && (!parsed.input || typeof parsed.input === 'object'
|
|
83
85
|
&& !Array.isArray(parsed.input) && Object.keys(parsed.input).length === 0)) return { args };
|
|
84
|
-
if ([
|
|
85
|
-
if (args
|
|
86
|
+
if (args[0] === 'billing' && args.length === 1 && !parsed.input) return { args };
|
|
87
|
+
if (installOptions(args) && !parsed.input) return { args };
|
|
86
88
|
if (args[0] === 'recurring' && ['list', 'claim'].includes(args[1] ?? '') && args.length === 2 && !parsed.input) return { args };
|
|
87
89
|
if (args[0] === 'recurring' && ['finish', 'runs'].includes(args[1] ?? '') && args.length === 3 && (!parsed.input || args[1] === 'finish')) return { args, ...(parsed.input ? { input: parsed.input } : {}) };
|
|
88
90
|
if (args[0] === 'usage' && args.length <= 2 && !parsed.input
|
|
@@ -96,9 +98,23 @@ export function installerCommand(parsed) {
|
|
|
96
98
|
if (!parsed || parsed.input || !['npx', 'npx.cmd'].includes(parsed.words[0])) return null;
|
|
97
99
|
const words = [...parsed.words]; words.shift();
|
|
98
100
|
while (['--yes', '--prefer-online', '--registry=https://registry.npmjs.org'].includes(words[0])) words.shift();
|
|
99
|
-
if (
|
|
100
|
-
|
|
101
|
-
|
|
101
|
+
if (!/^@entrorove\/skill(?:@(?:latest|\d+\.\d+\.\d+))?$/u.test(words[0])) return null;
|
|
102
|
+
const options = installOptions(words.slice(1));
|
|
103
|
+
if (!options) return null;
|
|
104
|
+
return `npx --yes --prefer-online --registry=https://registry.npmjs.org ${words[0]} install${options.hostId ? ' --host codex' : ''}${options.hooks ? ' --hooks' : ''}`;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export function installOptions(args) {
|
|
108
|
+
if (args[0] !== 'install') return null;
|
|
109
|
+
const options = { hooks: false }, seen = new Set();
|
|
110
|
+
for (let index = 1; index < args.length; index++) {
|
|
111
|
+
const key = args[index] === '--host' ? 'hostId' : ['--hooks', '--no-hooks'].includes(args[index]) ? 'hooks' : null;
|
|
112
|
+
if (!key || seen.has(key)) return null;
|
|
113
|
+
seen.add(key);
|
|
114
|
+
if (key === 'hostId') { if (args[++index] !== 'codex') return null; options.hostId = 'codex'; }
|
|
115
|
+
else options.hooks = args[index] === '--hooks';
|
|
116
|
+
}
|
|
117
|
+
return options;
|
|
102
118
|
}
|
|
103
119
|
|
|
104
120
|
export function readCommand(parsed) {
|
|
@@ -170,6 +186,6 @@ export function runtimeHashRead(parsed, runtime) {
|
|
|
170
186
|
|
|
171
187
|
export function renderSdkCommand(call, runtime, sessionId, host = process.env.ENTROROVE_IDE ?? 'Codex') {
|
|
172
188
|
const quote = value => `'${String(value).replace(/'/gu, "'\\''")}'`;
|
|
173
|
-
const header = `ENTROROVE_IDE=${quote(host)} ENTROROVE_SESSION=${quote(sessionId)} CODEX_THREAD_ID=${quote(sessionId)} ${[runtime.node, runtime.cli, ...call.args].map(quote).join(' ')}`;
|
|
189
|
+
const header = `ENTROROVE_HOOK_MODE='required' ENTROROVE_IDE=${quote(host)} ENTROROVE_SESSION=${quote(sessionId)} CODEX_THREAD_ID=${quote(sessionId)} ${[runtime.node, runtime.cli, ...call.args].map(quote).join(' ')}`;
|
|
174
190
|
return call.input ? `${header} <<'ENTROROVE_INPUT'\n${JSON.stringify(call.input)}\nENTROROVE_INPUT` : header;
|
|
175
191
|
}
|
package/ide-hook.mjs
CHANGED
|
@@ -14,6 +14,7 @@ import { verifyIdeLocalAcceptance } from './ide-local-acceptance.mjs';
|
|
|
14
14
|
import { registerIdeRequirement, ideQueueContext, unclassifiedIdeRequirements,
|
|
15
15
|
advanceIdeQueue, checkQueuedStart, unfinishedIdeQueue } from './ide-queue.mjs';
|
|
16
16
|
import { explicitIdeExit, markIdeExited } from './ide-exit.mjs';
|
|
17
|
+
import { appliesIdeHook, hasIdeHookSelection, selectsIdeHook, ideUserPrompt as userPrompt } from './ide-selection.mjs';
|
|
17
18
|
|
|
18
19
|
const output = (event, extra = {}) => ({ hookSpecificOutput: { hookEventName: event, ...extra } });
|
|
19
20
|
const deny = reason => output('PreToolUse', { permissionDecision: 'deny', permissionDecisionReason: reason });
|
|
@@ -25,14 +26,6 @@ const inputErrors = {
|
|
|
25
26
|
const publicId = value => typeof value === 'string' && /^[A-Za-z0-9_-]{1,200}$/u.test(value);
|
|
26
27
|
const readTools = new Set(['wait', 'view_image', 'list_mcp_resources', 'list_mcp_resource_templates', 'read_mcp_resource', 'web_search', 'update_plan', 'request_user_input', 'request_user_input_async', 'get_goal']);
|
|
27
28
|
const unlockCommand = 'entrorove unlock';
|
|
28
|
-
const selectPrompt = /^(?:(?:请)?(?:使用|启用)\s+\$?entrorove|\$entrorove)(?:\s|[,。,::!!]|$)/iu;
|
|
29
|
-
function userPrompt(event) {
|
|
30
|
-
let prompt = (event.prompt ?? '').trim();
|
|
31
|
-
for (const wrapper of ['**', '__', '`']) {
|
|
32
|
-
if (prompt.startsWith(wrapper) && prompt.endsWith(wrapper)) prompt = prompt.slice(wrapper.length, -wrapper.length).trim();
|
|
33
|
-
}
|
|
34
|
-
return prompt;
|
|
35
|
-
}
|
|
36
29
|
const managementOperations = new Set(['capabilities', 'help', 'start', 'continue', 'task-describe', 'flow-cancel', 'flow-abandon', 'scope-connect', 'mutation-connect', 'mutation-settle', 'mutation-consumption-attest', 'mutation-delegate-prepare', 'status', 'feedback', 'cloud-status', 'cloud-watch', 'queue', 'unlock', 'usage', 'billing', 'recurring']);
|
|
37
30
|
function operationOf(call) {
|
|
38
31
|
if (!call) return null;
|
|
@@ -155,15 +148,12 @@ function allowInstaller(event, state, command) {
|
|
|
155
148
|
return output('PreToolUse', { permissionDecision: 'allow', updatedInput: safeInput });
|
|
156
149
|
}
|
|
157
150
|
async function beforeTool(event, state, home) {
|
|
158
|
-
if (state.phase === 'user-exited') return {};
|
|
151
|
+
if (!hasIdeHookSelection(state) || state.phase === 'user-exited') return {};
|
|
159
152
|
const unlocked = await readBreakGlass(home, state.sessionId);
|
|
160
153
|
const command = event.tool_input?.command ?? event.tool_input?.cmd, parsed = literalCommand(command);
|
|
161
154
|
const isShell = ['Bash', 'exec_command', 'shell_command'].includes(event.tool_name);
|
|
162
155
|
const installer = isShell && installerCommand(parsed);
|
|
163
156
|
if (installer) return allowInstaller(event, state, installer);
|
|
164
|
-
const namedSdk = parsed?.words.some(word => word === 'entrorove' || /^@entrorove\/skill(?:@[^ ]+)?$/u.test(word)
|
|
165
|
-
|| /(?:@entrorove\/skill|entrorove-skill)\/cli\.mjs$/u.test(word));
|
|
166
|
-
if (!state.active && !namedSdk) return {};
|
|
167
157
|
const runtime = isShell && parsed ? await ideRuntime(home) : null;
|
|
168
158
|
const call = runtime && sdkCommand(parsed, runtime);
|
|
169
159
|
if (call) {
|
|
@@ -174,7 +164,6 @@ async function beforeTool(event, state, home) {
|
|
|
174
164
|
return output('PreToolUse', { permissionDecision: 'allow', updatedInput: prepareIdeShellInput(event.tool_name,
|
|
175
165
|
event.tool_input, renderSdkCommand(call, runtime, state.sessionId), true) });
|
|
176
166
|
}
|
|
177
|
-
state.active = true;
|
|
178
167
|
if (call.args[0] !== 'configure' && call.args[0] !== 'unlock') await bindIdeAccount(state, home);
|
|
179
168
|
if (state.phase === 'setup' && !unlocked && !isManagementCall(call)) return denyBlocked(state, event, 'Entrorove:自举阶段只放行 Entrorove 管理调用及主机明确授权的任务间报告;业务与写操作需先建立原 flow。');
|
|
180
169
|
if (call.args[0] === 'unlock') {
|
|
@@ -250,10 +239,11 @@ async function beforeTool(event, state, home) {
|
|
|
250
239
|
return denyBlocked(state, event, `Entrorove:已阻止原生 ${event.tool_name ?? 'unknown'} 调用。当前阶段 ${state.phase}${state.taskNumber ? `,云端任务 ${state.taskNumber}` : ''}。写入、删除、移动及不确定的终端操作必须使用原任务的 guarded-write/guarded-delete/guarded-move 或已批准的执行计划。`);
|
|
251
240
|
}
|
|
252
241
|
export async function runIdeHook(event, { home } = {}) {
|
|
253
|
-
|
|
242
|
+
if (!await appliesIdeHook(event, home)) return {};
|
|
243
|
+
try { return await ideSession(event, async state => {
|
|
254
244
|
const name = event.hook_event_name;
|
|
255
|
-
const selected =
|
|
256
|
-
const newSelection = selected && !state
|
|
245
|
+
const selected = selectsIdeHook(event);
|
|
246
|
+
const newSelection = selected && !hasIdeHookSelection(state);
|
|
257
247
|
if (name === 'UserPromptSubmit') {
|
|
258
248
|
state.turnSequence = (Number.isSafeInteger(state.turnSequence) ? state.turnSequence : 0) + 1;
|
|
259
249
|
delete state.stopNoticeTurn;
|
|
@@ -265,6 +255,7 @@ export async function runIdeHook(event, { home } = {}) {
|
|
|
265
255
|
}
|
|
266
256
|
if (selected) {
|
|
267
257
|
state.active = true;
|
|
258
|
+
state.hookSelection = { source: 'user-prompt', sessionId: state.sessionId, repositoryRoot: state.repositoryRoot };
|
|
268
259
|
if (['ended', 'user-exited'].includes(state.phase)) {
|
|
269
260
|
if (state.phase === 'ended') { delete state.flowId; delete state.taskId; delete state.taskNumber; delete state.requestId; }
|
|
270
261
|
state.phase = state.exitPhase ?? 'entry'; delete state.exitPhase;
|
|
@@ -327,7 +318,7 @@ export async function runIdeHook(event, { home } = {}) {
|
|
|
327
318
|
}
|
|
328
319
|
}
|
|
329
320
|
return state.active && ['SessionStart','UserPromptSubmit','PostCompact','PreCompact'].includes(name) ? output(name, { additionalContext: `${ideContext(state)}${ideQueueContext(state)}` }) : {};
|
|
330
|
-
}, home);
|
|
321
|
+
}, home); } catch (cause) { cause.entroroveHookSelected = true; throw cause; }
|
|
331
322
|
}
|
|
332
323
|
let incomingEvent;
|
|
333
324
|
async function readHookEvent() {
|
|
@@ -349,11 +340,13 @@ async function main() {
|
|
|
349
340
|
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
350
341
|
}
|
|
351
342
|
if (process.argv[1] && realpathSync(process.argv[1]) === fileURLToPath(import.meta.url)) main().catch(cause => {
|
|
352
|
-
//
|
|
353
|
-
//
|
|
343
|
+
// Deny only a positively selected session. Unidentified transport failures
|
|
344
|
+
// must not stop unrelated host work or expose input, credentials or paths.
|
|
354
345
|
const reason = Object.hasOwn(inputErrors, cause?.code) ? inputErrors[cause.code]
|
|
355
346
|
: `Entrorove 安全检查失败;本次工具调用已阻止。可复制解锁命令:${unlockCommand}`;
|
|
356
|
-
const result =
|
|
357
|
-
|
|
347
|
+
const result = !cause.entroroveHookSelected ? { systemMessage: Object.hasOwn(inputErrors, cause?.code)
|
|
348
|
+
? inputErrors[cause.code] : 'Entrorove hook 无法确认选用会话;本次未接管,原状态已保留。' }
|
|
349
|
+
: incomingEvent === 'Stop' ? { decision: 'block', reason } : incomingEvent === 'PreToolUse' ? deny(reason)
|
|
350
|
+
: { continue: false, stopReason: reason, systemMessage: reason };
|
|
358
351
|
process.stdout.write(`${JSON.stringify(result)}\n`);
|
|
359
352
|
});
|
package/ide-install.mjs
CHANGED
|
@@ -5,7 +5,7 @@ import { ideDirectory, ideDigest, readIdeJson, writeIdeJson, ideError } from './
|
|
|
5
5
|
import { withStateLock } from './local-state-lock.mjs';
|
|
6
6
|
|
|
7
7
|
const source = path.dirname(fileURLToPath(import.meta.url));
|
|
8
|
-
const files = ['ide-hook.mjs', 'ide-session.mjs', 'ide-exit.mjs', 'break-glass.mjs', 'ide-results.mjs', 'ide-local-acceptance.mjs', 'ide-queue.mjs', 'ide-command.mjs', 'ide-code-mode.mjs', 'remote-transport.mjs', 'local-credential.mjs', 'local-state-lock.mjs', 'local-stage-boundary.mjs'];
|
|
8
|
+
const files = ['ide-hook.mjs', 'ide-session.mjs', 'ide-selection.mjs', 'ide-exit.mjs', 'break-glass.mjs', 'ide-results.mjs', 'ide-local-acceptance.mjs', 'ide-queue.mjs', 'ide-command.mjs', 'ide-code-mode.mjs', 'remote-transport.mjs', 'local-credential.mjs', 'local-state-lock.mjs', 'local-stage-boundary.mjs'];
|
|
9
9
|
const quote = text => `'${text.replace(/'/gu, "'\\''")}'`;
|
|
10
10
|
|
|
11
11
|
// One shared host-agnostic hook binary; every host is described by its own
|
|
@@ -96,7 +96,7 @@ async function directoryExists(directory) {
|
|
|
96
96
|
}
|
|
97
97
|
export async function activeIdeAdapters({ home, environment = process.env } = {}) {
|
|
98
98
|
const directory = await ideDirectory(home).catch(cause => {
|
|
99
|
-
if (cause.code
|
|
99
|
+
if (['ENOENT', 'ENTROROVE_CREDENTIAL_MISSING'].includes(cause.code)) return null;
|
|
100
100
|
throw cause;
|
|
101
101
|
});
|
|
102
102
|
if (!directory) return [];
|
|
@@ -166,12 +166,12 @@ export async function installIdeHooks({ home, version, packageDirectory = source
|
|
|
166
166
|
message: `已写入 Entrorove Hook 配置(${installed.map(item => item.host).join('、')});需由 IDE 信任并收到真实回调后才能确认生效。` };
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
-
export async function uninstallIdeHooks({ home }) {
|
|
170
|
-
const directory = await ideDirectory(home).catch(error => { if (error.code
|
|
169
|
+
export async function uninstallIdeHooks({ home, adapters = ideAdapters }) {
|
|
170
|
+
const directory = await ideDirectory(home).catch(error => { if (['ENOENT', 'ENTROROVE_CREDENTIAL_MISSING'].includes(error.code)) return null; throw error; });
|
|
171
171
|
if (!directory) return { removed: [], preserved: [] };
|
|
172
172
|
const removed = [], preserved = [], records = [];
|
|
173
173
|
const hookPath = path.join(directory, 'ide-hook.mjs');
|
|
174
|
-
for (const adapter of
|
|
174
|
+
for (const adapter of adapters) {
|
|
175
175
|
const recordPath = path.join(directory, adapter.record), record = await readIdeJson(recordPath);
|
|
176
176
|
if (record && (record.schemaVersion !== 'entrorove.ide-installation/1.0' || record.host !== adapter.host)) {
|
|
177
177
|
throw ideError('ENTROROVE_IDE_STORE', `${adapter.host} installation record is invalid; it was preserved`);
|
|
@@ -206,6 +206,8 @@ export async function uninstallIdeHooks({ home }) {
|
|
|
206
206
|
if (record) await fs.rm(recordPath);
|
|
207
207
|
});
|
|
208
208
|
}
|
|
209
|
+
// Disabling Codex must not remove the shared runtime used by another host.
|
|
210
|
+
if ((await fs.readdir(directory)).some(name => /^installation(?:-[a-z0-9-]+)?\.json$/u.test(name))) return { removed, preserved };
|
|
209
211
|
const digests = new Map();
|
|
210
212
|
for (const record of records) for (const [name, digest] of Object.entries(record.files ?? {})) {
|
|
211
213
|
if (!digests.has(name)) digests.set(name, new Set());
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { promises as fs } from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { ideDirectory, ideDigest, readIdeJson } from './ide-session.mjs';
|
|
4
|
+
import { explicitIdeExit } from './ide-exit.mjs';
|
|
5
|
+
|
|
6
|
+
const selection = /^(?:(?:请)?(?:使用|启用)\s+\$?entrorove|\$entrorove)(?:\s|[,。,::!!]|$)/iu;
|
|
7
|
+
export function ideUserPrompt(event) {
|
|
8
|
+
let prompt = typeof event.prompt === 'string' ? event.prompt.trim() : '';
|
|
9
|
+
for (const wrapper of ['**', '__', '`']) {
|
|
10
|
+
if (prompt.startsWith(wrapper) && prompt.endsWith(wrapper)) prompt = prompt.slice(wrapper.length, -wrapper.length).trim();
|
|
11
|
+
}
|
|
12
|
+
return prompt;
|
|
13
|
+
}
|
|
14
|
+
export const selectsIdeHook = event => event.hook_event_name === 'UserPromptSubmit' && selection.test(ideUserPrompt(event));
|
|
15
|
+
export const hasIdeHookSelection = state => state?.active === true && state.hookSelection?.source === 'user-prompt'
|
|
16
|
+
&& state.hookSelection.sessionId === state.sessionId && state.hookSelection.repositoryRoot === state.repositoryRoot;
|
|
17
|
+
|
|
18
|
+
// Global callbacks must be inert until this exact session and repository opt in.
|
|
19
|
+
// In particular, discovery, an old active bit, and a broken store cannot select it.
|
|
20
|
+
export async function appliesIdeHook(event, home) {
|
|
21
|
+
if (typeof event?.session_id !== 'string' || !/^[A-Za-z0-9_-]{1,200}$/u.test(event.session_id)
|
|
22
|
+
|| typeof event.cwd !== 'string' || !path.isAbsolute(event.cwd)) return false;
|
|
23
|
+
if (selectsIdeHook(event)) return true;
|
|
24
|
+
try {
|
|
25
|
+
const directory = await ideDirectory(home);
|
|
26
|
+
const state = await readIdeJson(path.join(directory, `session-${ideDigest(event.session_id)}.json`));
|
|
27
|
+
const exiting = event.hook_event_name === 'UserPromptSubmit' && explicitIdeExit(ideUserPrompt(event));
|
|
28
|
+
return state?.sessionId === event.session_id && (hasIdeHookSelection(state) || exiting)
|
|
29
|
+
&& await fs.realpath(event.cwd) === state.repositoryRoot;
|
|
30
|
+
} catch { return false; }
|
|
31
|
+
}
|
package/ide-session.mjs
CHANGED
|
@@ -152,8 +152,11 @@ async function declaredHost(environment) {
|
|
|
152
152
|
return null;
|
|
153
153
|
}
|
|
154
154
|
export async function assertIdeExecution(args, input, { home = os.homedir(), environment = process.env } = {}) {
|
|
155
|
+
approvedResultContext = undefined;
|
|
156
|
+
if (environment.ENTROROVE_HOOK_MODE === undefined) return { mode: 'explicit-sdk', hookEnforced: false };
|
|
157
|
+
if (environment.ENTROROVE_HOOK_MODE !== 'required') throw ideError('ENTROROVE_IDE_MODE', 'Unknown Entrorove hook execution mode');
|
|
155
158
|
const { host, sessionId } = ideGuardBinding(environment);
|
|
156
|
-
if (!host || host === 'Entrorove CLI')
|
|
159
|
+
if (!host || host === 'Entrorove CLI') throw ideError('ENTROROVE_IDE_GUARD_UNSUPPORTED', 'Hook execution requires its actual IDE host and session');
|
|
157
160
|
const lifecycle = args[0] === 'local' ? args[1] : args[0] === 'invoke' ? input?.operation : null;
|
|
158
161
|
if (['flow-cancel', 'flow-abandon'].includes(lifecycle) && await readBreakGlass(home, sessionId)) {
|
|
159
162
|
const flowId = args[0] === 'invoke' ? input?.input?.flowId : input?.flowId;
|
|
@@ -177,13 +180,15 @@ export async function assertIdeExecution(args, input, { home = os.homedir(), env
|
|
|
177
180
|
const directory = await ideDirectory(home), state = await readIdeJson(path.join(directory, `session-${ideDigest(sessionId)}.json`));
|
|
178
181
|
const expected = ideDigest({ args, input });
|
|
179
182
|
const approved = [state?.pendingCall, ...Object.values(state?.readCalls ?? {})].find(call => call?.inputDigest === expected);
|
|
180
|
-
if (!state?.active ||
|
|
183
|
+
if (!state?.active || state.hookSelection?.source !== 'user-prompt' || state.hookSelection.sessionId !== sessionId
|
|
184
|
+
|| state.hookSelection.repositoryRoot !== state.repositoryRoot || !approved || state.sessionId !== sessionId
|
|
181
185
|
|| Date.now() - Date.parse(state.observedAt) > 120_000) {
|
|
182
186
|
throw ideError('ENTROROVE_IDE_GUARD_REQUIRED', `${host} tool guard has not approved this exact call. Run install, accept the host hook, and resume the original task.`);
|
|
183
187
|
}
|
|
184
188
|
await bindIdeAccount(state, home);
|
|
185
189
|
approvedResultContext = { home, sessionId: state.sessionId, repositoryRoot: state.repositoryRoot,
|
|
186
190
|
accountDigest: state.accountDigest, toolUseId: approved.toolUseId, inputDigest: expected };
|
|
191
|
+
return { mode: 'hook-enforced', hookEnforced: true };
|
|
187
192
|
}
|
|
188
193
|
|
|
189
194
|
export async function settleBreakGlassSession(args, input, result, { home = os.homedir(), environment = process.env } = {}) {
|
package/manifest.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@entrorove/skill",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.61",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"entrorove": "cli.mjs"
|
|
@@ -222,6 +222,7 @@
|
|
|
222
222
|
"ide-code-mode.mjs",
|
|
223
223
|
"ide-command.mjs",
|
|
224
224
|
"ide-hook.mjs",
|
|
225
|
+
"ide-selection.mjs",
|
|
225
226
|
"ide-install.mjs",
|
|
226
227
|
"install-cleanup.mjs",
|
|
227
228
|
"ide-session.mjs",
|
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.61",
|
|
4
|
+
"digest": "8211a23e233808dfc8f43dd0b28af5eae9b8bea5127b9550da8e8c50d9447052",
|
|
5
5
|
"files": {
|
|
6
6
|
"connected-cli.mjs": "79c3359303957a9ebb8987e3dfb181f189d380fa02ef4462683b786aedfc7802",
|
|
7
7
|
"local-approved-process.mjs": "442856df788e63f38757439ba0657d1c689aaf797631a955fae3dd639e844e6d",
|
|
@@ -22,10 +22,10 @@
|
|
|
22
22
|
"mutation-client.mjs": "6455c35b483d6d22e42e7be708630db07d9fd1d3cdf639294b126b69db2eae2f",
|
|
23
23
|
"cloud-mutation-authority.mjs": "c7226e882a4f3be4d2f55728f515d5a815c0aa1f21aa5e4689314e6e6a8c66a2",
|
|
24
24
|
"ide-code-mode.mjs": "f8ba4de33632ab4c6df52dab52f392414b4632c7e94b218b8065677970c075c7",
|
|
25
|
-
"ide-command.mjs": "
|
|
26
|
-
"ide-hook.mjs": "
|
|
27
|
-
"ide-install.mjs": "
|
|
28
|
-
"ide-session.mjs": "
|
|
25
|
+
"ide-command.mjs": "dbdb4cbf8e870c93a746ca176cbbdeffc0458de1293583d3eb9af4c256541370",
|
|
26
|
+
"ide-hook.mjs": "c44d37997fae55bd113ff9044947c54152aaccdf081d0f39d437179d33e9a4e2",
|
|
27
|
+
"ide-install.mjs": "1c80e191ddc2ac8789f0c71edc7bc8c3c8cea6bfab537cdf6baffa4a6ce3419c",
|
|
28
|
+
"ide-session.mjs": "5277a6ea3445bfa9b2e28847372d963da77787d472d0414c0e253d4fe29f74ec",
|
|
29
29
|
"break-glass.mjs": "6ec9f97c5d68bb33121b2374c06b9d4c8eb3419b52d00849fec7124bc63e4582",
|
|
30
30
|
"ide-results.mjs": "baa0618845ced901334644479bf4e0d298bad3f955bc18846752de6c283a5573",
|
|
31
31
|
"ide-local-acceptance.mjs": "238eec6d7b6093fb8ad022da0ed3383a48ba2ffcf693e3ce8a241cf9624088d8",
|
|
@@ -50,7 +50,7 @@
|
|
|
50
50
|
"runtime/validator-runtime-v7.0.44.d.mts": "7797edbfe2f7de24da370204dce4dfd22822a1bd80df93514fff900b98afe36f",
|
|
51
51
|
"snapshot-retention.mjs": "ca46aeb36b1a5a24fe7e967031a71b9a3d33f40cb715d344402cbe0dc9c425cb",
|
|
52
52
|
"snapshot-cleanup-journal.mjs": "76a9684cc95b4eb076e1298d78a9dff37948b00d9607b8f546c599072d3ed331",
|
|
53
|
-
"IDE-EXECUTION.md": "
|
|
53
|
+
"IDE-EXECUTION.md": "203aa4ae47cc45915e1a89bd7fbb56bf57aebccef444599b3a2d1d2816f01907",
|
|
54
54
|
"REUSE-DISCIPLINE.md": "5b214cf313e7f715f52d54e28093a2d038f0f196ca64b15d1c49587b9d8eecf8",
|
|
55
55
|
"reuse-discipline-release.mjs": "7f55ae10ec3396ed3bc5430a0c64f94c33c2dfbc57b32084caab92fd5fd1586f",
|
|
56
56
|
"local-final-gate16.mjs": "083aec470670e6cdb7ad2ab27b7a51b53a9ec3a8b4121cb9cbfa17d9940892c2",
|
|
@@ -94,18 +94,19 @@
|
|
|
94
94
|
"local-autocoord17-waits.mjs": "2b0a713987822548a94e1ed3a9a891532db45383797dfc5d5bc8d1e35593cf25",
|
|
95
95
|
"local-validator-isolation17.mjs": "48e94604e28b8fddd567dfb35ff60b73fd094a5803bd49f076388b7f310f92aa",
|
|
96
96
|
"local-calctool-composition17.mjs": "ac89fcb41ab0d0d9b47c1b5696945281b0894eb064820775e36a011c76314e6a",
|
|
97
|
-
"cli.mjs": "
|
|
97
|
+
"cli.mjs": "b28bfda3d9ec610c7865725eff4e5d551bcbdfc8847f6fd43eca845ce3881ea8",
|
|
98
|
+
"ide-selection.mjs": "e11e2b363c06444f1dcb4cdab1eaa0eb748a379b84354e0e71fd9c2dc79a4815",
|
|
98
99
|
"ide-exit.mjs": "c890c7b34fa6f12e0ccff7a7b85738d515fb13ad93f671a8547ae6570b66488d",
|
|
99
100
|
"install-cleanup.mjs": "8a8e1a7dfe37427f86cd4d6e317890d0829894a9949d4216674a716b36edbc54",
|
|
100
101
|
"review-client.mjs": "3491eef68ed533174b31db3c53febb6519b8f088f71a9964644714a9a4c03c77",
|
|
101
102
|
"version.mjs": "1f392147d72c40af4b03b307ea607075fb815af5174fa07e254b95fe12dbf3e7",
|
|
102
|
-
"SKILL.md": "
|
|
103
|
+
"SKILL.md": "f04566431da716ff61812118004ca69f2a8f9f24fe4e032f2a1fff5073b8071b",
|
|
103
104
|
"CAPABILITY-MAP.md": "e420bbc202c27d983635ae33b823b39dd445cf5cdf40ffe88e210a755cb7424d",
|
|
104
105
|
"AGREEMENT.md": "f93a68e92c457200dd024610e65f74e478b8f60860f951da818b70561f1b9bf8",
|
|
105
106
|
"DELIVERY-BOUNDARIES.md": "9b9db50ed1bcce9e77ff6527b6bb7eaf12f3b913162ea9cb7fe90db06b393a4f",
|
|
106
|
-
"package.json": "
|
|
107
|
+
"package.json": "ce0f78910ec9aeb36a7d61a30a68c6b117c9b29ca34cc8446a46604b251c131e",
|
|
107
108
|
"manifest.json": "ab06e307795bc9da5add926752b6c4dbdaf18625090261a035aa356a679c504f",
|
|
108
|
-
"release.mjs": "
|
|
109
|
+
"release.mjs": "90e4c5beb05e263c2cacf09c476480ac3599a965d62e0adda68226a8baaa968c",
|
|
109
110
|
"local-cli.mjs": "41e2a737c8587cb5ce469a7661f6d14b5ea4cd073f8286822fc4dc96b67f56a1",
|
|
110
111
|
"local-state-lock.mjs": "1dbf64264642a0851faf043e07ee9f66d2ad0508e9f799b0626246e42fae893e",
|
|
111
112
|
"local-execution.mjs": "185f34e917440a360b3c4bafd3af245243807d964ae3820b3cffaaa2e6348cc6",
|
package/release.mjs
CHANGED
|
@@ -68,7 +68,7 @@ const sourceFiles = [
|
|
|
68
68
|
'local-merge-transaction.mjs',
|
|
69
69
|
...swarmSourceFiles,
|
|
70
70
|
...coordination17SourceFiles,
|
|
71
|
-
'cli.mjs', 'ide-exit.mjs', 'install-cleanup.mjs', 'review-client.mjs', 'version.mjs', 'SKILL.md', 'CAPABILITY-MAP.md', 'AGREEMENT.md', 'DELIVERY-BOUNDARIES.md',
|
|
71
|
+
'cli.mjs', 'ide-selection.mjs', 'ide-exit.mjs', 'install-cleanup.mjs', 'review-client.mjs', 'version.mjs', 'SKILL.md', 'CAPABILITY-MAP.md', 'AGREEMENT.md', 'DELIVERY-BOUNDARIES.md',
|
|
72
72
|
'package.json', 'manifest.json', 'release.mjs',
|
|
73
73
|
'local-cli.mjs', 'local-state-lock.mjs', 'local-execution.mjs', 'local-integrity.mjs', 'local-evidence-verification.mjs', 'local-formula.mjs', 'local-ledger.mjs',
|
|
74
74
|
'local-error.mjs',
|
package/releases.json
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.1.61",
|
|
4
|
+
"date": "2026-10-18",
|
|
5
|
+
"zh": "钩子改为可选:默认安装关闭钩子,IDE 可直接调用 SDK;只有明确选用技能的原会话与仓库启用拦截,普通查询、旧激活状态及无法归属的事件不再接管其他任务。保留账号、写入范围、签名和真实本地验收校验。",
|
|
6
|
+
"en": "Make hooks optional: default installs disable hooks and IDEs can call the SDK directly. Interception requires explicit selection of the original session and repository; discovery, legacy activation and unidentified events cannot govern unrelated work. Preserve account, mutation scope, signatures and actual local acceptance checks."
|
|
7
|
+
},
|
|
2
8
|
{
|
|
3
9
|
"version": "0.1.60",
|
|
4
10
|
"date": "2026-10-17",
|