@entrorove/skill 0.1.31 → 0.1.32

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 CHANGED
@@ -1,5 +1,10 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.32 — 2026-10-11
4
+
5
+ - 增加云端沙箱状态与用量只读查询,并支持按任务直接读取真实状态。
6
+ - Added read-only cloud sandbox status and direct reads of authoritative task state and usage.
7
+
3
8
  ## 0.1.31 — 2026-10-11
4
9
 
5
10
  - 修复云端沙箱任务响应处理并保留可继续的任务上下文。
package/SKILL.md CHANGED
@@ -5,7 +5,7 @@ description: An engineering skill that understands a task, chooses a fitting wor
5
5
 
6
6
  # entrorove · 熵巡
7
7
 
8
- Version: 0.1.31.
8
+ Version: 0.1.32.
9
9
 
10
10
  Read the user's goal and repository instructions first. Preserve the original task through planning, execution and verification. Use the workflow only where it helps; a small, low-risk edit can proceed directly. Never claim a reported step is a verified result.
11
11
 
@@ -25,11 +25,13 @@ On first use or after a material agreement revision, the CLI returns a Confirm P
25
25
 
26
26
  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.
27
27
 
28
- `start` creates a normal durable skill flow. It does not create a cloud-sandbox task or contribute to cloud-sandbox usage. To create a real cloud-sandbox task, call `operation: "cloud-task"` with `input.goal`; the CLI returns a Confirm Protocol choice interaction before any cloud request. Continue the same request with `sandboxChoice: "use"` or `sandboxChoice: "local"`. `use` calls the authenticated `/api/cloud-task` endpoint and returns the real `taskId`; `local` skips only this task. A `needs-input`, `blocked` or `failed` result is not a successful dispatch and must be shown to the user.
28
+ `start` creates a normal durable skill flow. It does not create a cloud-sandbox task or contribute to cloud-sandbox usage. To create a real cloud-sandbox task, call `operation: "cloud-task"` with `input.goal`; the CLI returns a Confirm Protocol choice interaction before any cloud request. Continue the same request with `sandboxChoice: "use"` or `sandboxChoice: "local"`. `use` calls the authenticated `/api/cloud-task` endpoint and returns the real `taskId`; `local` skips only this task. The server is authoritative for account entitlement and the account-wide sandbox preference: a disabled or unavailable account returns `blocked` and creates no task. A `needs-input`, `blocked` or `failed` result is not a successful dispatch and must be shown to the user.
29
+
30
+ After dispatch, query the real task without resending it with the CLI-only `operation: "cloud-status"` and `input.taskId`, or `npx @entrorove/skill cloud-status` with the same JSON. This special CLI route reads the authoritative task list and usage endpoints; it is not part of the `/api/skill/invoke` capability map. The read-only result includes the current task status, public title/summary, and recorded model usage when available. A missing task is reported explicitly; it is never treated as completed. This is the skill-side status and usage check for cloud tasks; the web dock may additionally subscribe to its event stream.
29
31
 
30
32
  ### Per-task cloud sandbox choice
31
33
 
32
- 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, use the cloud sandbox by the host's stated timeout default. 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 account-wide preference is disabled or unavailable, do not dispatch a cloud task and do not show a misleading per-task prompt; preserve the normal local workflow and report the prerequisite clearly. This choice never bypasses the normal task schema, mutation authority, evidence checks, or risk confirmation.
34
+ 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, use the cloud sandbox by the host's stated timeout default. 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.
33
35
 
34
36
  ```json
35
37
  {"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}}}
package/cli.mjs CHANGED
@@ -12,7 +12,7 @@ import { runTaskMessageCli } from './task-message-cli.mjs';
12
12
  import { apiUrl, buildInvocation, invokeRemote, queryFlows, queryStatus } from './remote-client.mjs';
13
13
  const packageDir = path.dirname(fileURLToPath(import.meta.url));
14
14
  import { buildReview, submitSkillFeedback, feedbackNoticeVersion } from './review-client.mjs';
15
- import { runCloudTask as dispatchCloudTask } from './cloud-task-client.mjs';
15
+ import { queryCloudTask, runCloudTask as dispatchCloudTask } from './cloud-task-client.mjs';
16
16
  const markerName = '.entrorove-managed.json';
17
17
  const installFiles = ['SKILL.md', 'CAPABILITY-MAP.md', 'AGREEMENT.md', 'manifest.json'];
18
18
  const markerSchema = 'entrorove.managed-install/1.0';
@@ -389,10 +389,20 @@ export async function runCloudTask(input, dependencies = remoteDependencies()) {
389
389
  return result;
390
390
  }
391
391
 
392
+ export async function runCloudStatus(input, dependencies = remoteDependencies()) {
393
+ const result = await queryCloudTask(input?.taskId, dependencies);
394
+ process.stdout.write(`${JSON.stringify(result)}\n`);
395
+ if (['blocked', 'failed', 'missing'].includes(result.status)) process.exitCode = 2;
396
+ return result;
397
+ }
398
+
392
399
  async function invoke(data) {
393
400
  if (data?.operation === 'cloud-task') {
394
401
  return runCloudTask(data.input, remoteDependencies());
395
402
  }
403
+ if (data?.operation === 'cloud-status') {
404
+ return runCloudStatus(data.input, remoteDependencies());
405
+ }
396
406
  return invokeRemote(data, remoteDependencies());
397
407
  }
398
408
 
@@ -423,6 +433,8 @@ async function main() {
423
433
  await runTaskMessageCli(args, await stdinJson(), remoteDependencies());
424
434
  } else if (command === 'cloud-task' && args.length === 0) {
425
435
  await runCloudTask(await stdinJson());
436
+ } else if (command === 'cloud-status' && args.length === 0) {
437
+ await runCloudStatus(await stdinJson());
426
438
  } else if (command === 'review' && args.length === 0) {
427
439
  await submitReview(await stdinJson());
428
440
  } else if (command === 'status' && args.length === 1) {
@@ -444,7 +456,7 @@ async function main() {
444
456
  } else if (command === 'local') {
445
457
  await runLocal(args);
446
458
  } else {
447
- throw new Error('Usage: entrorove install | configure | agreement | invoke | host-message [adapterModulePath] | cloud-task | status <requestId> | flows | review | local (JSON on stdin)');
459
+ throw new Error('Usage: entrorove install | configure | agreement | invoke | host-message [adapterModulePath] | cloud-task | cloud-status | status <requestId> | flows | review | local (JSON on stdin)');
448
460
  }
449
461
  }
450
462
  if (process.argv[1] && realpathSync(process.argv[1]) === realpathSync(fileURLToPath(import.meta.url))) {
@@ -3,6 +3,7 @@ import { appendInvocation } from './local-invocations.mjs';
3
3
  import { parseTransportResponse, requestTransport, trustedOrigin } from './remote-transport.mjs';
4
4
 
5
5
  const CLOUD_TASK_SCHEMA = 'entrorove.cloud-task/1.0';
6
+ const CLOUD_STATUS_SCHEMA = 'entrorove.cloud-status/1.0';
6
7
  const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
7
8
 
8
9
  function canonical(value) {
@@ -38,6 +39,11 @@ function validateDependencies(dependencies) {
38
39
  }
39
40
  }
40
41
 
42
+ function validateTaskId(taskId) {
43
+ if (typeof taskId !== 'string' || !UUID.test(taskId)) throw new Error('cloud-status taskId must be a UUID');
44
+ return taskId;
45
+ }
46
+
41
47
  export function sandboxChoiceInteraction(id) {
42
48
  return {
43
49
  schemaVersion: 'confirm.interaction/1.0', requestId: id, type: 'choice',
@@ -117,3 +123,53 @@ export async function runCloudTask(input, dependencies) {
117
123
  executionIsolation: typeof result.executionIsolation === 'string' ? result.executionIsolation : 'worker' });
118
124
  }
119
125
 
126
+ function publicTask(task) {
127
+ if (!task || typeof task !== 'object' || Array.isArray(task)) return null;
128
+ const allowed = ['id', 'status', 'displayTitle', 'titleStatus', 'titleError', 'summary', 'ideTaskId',
129
+ 'createdAt', 'updatedAt', 'completedAt'];
130
+ return Object.fromEntries(allowed.filter(key => task[key] !== undefined).map(key => [key, task[key]]));
131
+ }
132
+
133
+ function publicUsage(value) {
134
+ if (!Array.isArray(value)) return [];
135
+ const allowed = ['usageId', 'requestId', 'operation', 'attempt', 'meterKind', 'state', 'tokenStatus',
136
+ 'inputTokens', 'outputTokens', 'durationMs', 'durationBasis', 'providerId', 'modelId'];
137
+ return value.filter(item => item && typeof item === 'object' && !Array.isArray(item))
138
+ .map(item => Object.fromEntries(allowed.filter(key => item[key] !== undefined).map(key => [key, item[key]])));
139
+ }
140
+
141
+ export async function queryCloudTask(taskId, dependencies) {
142
+ const id = validateTaskId(taskId);
143
+ validateDependencies(dependencies);
144
+ await dependencies.install();
145
+ if (!await dependencies.agreementAccepted(dependencies.home)) {
146
+ return { schemaVersion: CLOUD_STATUS_SCHEMA, status: 'blocked', taskId: id,
147
+ code: 'agreement-required', interaction: dependencies.agreementRequired(dependencies.home) };
148
+ }
149
+ const token = await dependencies.readCredential(dependencies.home);
150
+ const origin = trustedOrigin(dependencies.apiOrigin());
151
+ const metadata = { kind: 'remote', operation: 'cloud-status', requestId: requestId({ taskId: id }) };
152
+ const taskResponse = await requestTransport(origin, `/api/cloud-sandbox/tasks/${id}`, { headers: { authorization: `Bearer ${token}` } });
153
+ let taskBody;
154
+ try { taskBody = await responseBody(taskResponse); } catch { taskBody = null; }
155
+ if (!taskResponse.ok || !taskBody?.task || taskBody.task.id !== id) {
156
+ await appendInvocation({ ...metadata, event: 'rejected' }, dependencies.home);
157
+ return { schemaVersion: CLOUD_STATUS_SCHEMA, status: taskResponse.status === 403 ? 'blocked' : taskResponse.status === 404 ? 'missing' : 'failed', taskId: id,
158
+ code: typeof taskBody?.error === 'string' ? taskBody.error : taskResponse.status === 404 ? 'cloud-task-not-found' : 'cloud-status-unavailable', httpStatus: taskResponse.status };
159
+ }
160
+ const task = taskBody.task;
161
+ let usage = [];
162
+ let usageError;
163
+ const usageResponse = await requestTransport(origin, `/api/cloud-sandbox/tasks/${id}/usage`, {
164
+ headers: { authorization: `Bearer ${token}` },
165
+ });
166
+ try {
167
+ const usageBody = await responseBody(usageResponse);
168
+ if (usageResponse.ok) usage = publicUsage(usageBody?.usage);
169
+ else usageError = typeof usageBody?.error === 'string' ? usageBody.error : 'cloud-usage-unavailable';
170
+ } catch { usageError = 'cloud-usage-invalid-response'; }
171
+ await appendInvocation({ ...metadata, event: 'status' }, dependencies.home);
172
+ return { schemaVersion: CLOUD_STATUS_SCHEMA, status: 'observed', taskId: id,
173
+ taskStatus: task.status, task: publicTask(task), usage, ...(usageError ? { usageError } : {}) };
174
+ }
175
+
package/manifest.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": "entrorove.skill-manifest/1.0",
3
3
  "name": "entrorove",
4
- "version": "0.1.31",
4
+ "version": "0.1.32",
5
5
  "endpoint": "https://entrorove.com",
6
6
  "requestSchemaVersion": "entrorove.skill.request/2.0",
7
7
  "supportedRequestSchemaVersions": [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@entrorove/skill",
3
- "version": "0.1.31",
3
+ "version": "0.1.32",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "entrorove": "cli.mjs"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": "entrorove.release-state/1.0",
3
- "version": "0.1.31",
4
- "digest": "005df83b58c713b893d715a7480c08a91896301f6295746525f49abd2d746044",
3
+ "version": "0.1.32",
4
+ "digest": "615bc63383071e3a1356d129b2c072e1641744f6b82def3ec0c2f56fa68a39a4",
5
5
  "files": {
6
6
  "local-final-gate16.mjs": "b30caab08441449ad556a6e9a3cefbf91190f0b3f7370f46d2a21156375aa8e3",
7
7
  "local-final-gate16-checks.mjs": "1dd30e9666d458d8b12ca6e4975f6f0ac8450c3ea9cbecc7401ae037f66b589a",
@@ -44,10 +44,10 @@
44
44
  "local-autocoord17-waits.mjs": "2b0a713987822548a94e1ed3a9a891532db45383797dfc5d5bc8d1e35593cf25",
45
45
  "local-validator-isolation17.mjs": "48e94604e28b8fddd567dfb35ff60b73fd094a5803bd49f076388b7f310f92aa",
46
46
  "local-calctool-composition17.mjs": "ac89fcb41ab0d0d9b47c1b5696945281b0894eb064820775e36a011c76314e6a",
47
- "cli.mjs": "6b2f31ee3204c8584ac4733a9b2d1c6ca72e2ea205e84f8a314a68f31917f629",
47
+ "cli.mjs": "6d455d8e22fccd24332726de6821a8a99f628d057648c9aae7c6262d89745722",
48
48
  "review-client.mjs": "3491eef68ed533174b31db3c53febb6519b8f088f71a9964644714a9a4c03c77",
49
49
  "version.mjs": "1f392147d72c40af4b03b307ea607075fb815af5174fa07e254b95fe12dbf3e7",
50
- "SKILL.md": "fa3fa41f1551e54512de0cae7940e2d7ad670f81a46c2e642cdc2323b171224f",
50
+ "SKILL.md": "20c09094ffd094fa59f73a26b8cbb987cf40a8247368bb5b6417695831ed2a70",
51
51
  "CAPABILITY-MAP.md": "128ecc8d90b2c17846ce6f0c650eada9e7fa7240f5d3c03b31e3ee01135557b8",
52
52
  "AGREEMENT.md": "f93a68e92c457200dd024610e65f74e478b8f60860f951da818b70561f1b9bf8",
53
53
  "package.json": "77e29f7740cc2a2284490a992a9945fbb4a3ad3ac044f4ff9a59b1aa83e44ae0",
@@ -118,7 +118,7 @@
118
118
  "local-scope-workspaces.mjs": "a44c34537e5ed2dcaf193a985e5bc05957989fbb160a650f9e37ba7d66eb2de8",
119
119
  "local-task-routing.mjs": "e26d6f1ba134ffe1da2a49b4fb6bb6dfa5617671f774a08e719d04f202cf5eca",
120
120
  "remote-client.mjs": "ce16258faffb09c9db19609d47a0af6f63fcbc256feb35ba7a14bbb89e69cc6e",
121
- "cloud-task-client.mjs": "b7dc4be6c4d2a60404538e3d875cf95533e1b7be3f43ac7f5d49118042ce1d45",
121
+ "cloud-task-client.mjs": "ca6c5af7f7c2507680fcce3b8ab739a50ebed88f5a202cffbecea962861bbebb",
122
122
  "remote-transport.mjs": "5e5a8c0b490371f7f5a052cffbeee6202d4cf713dff1c43b6d910fe944f8429c",
123
123
  "local-credential.mjs": "2a302a7f67b5ea8dc73453fc96ab33db349b59ca11fa9456e48ca1d9669d877c",
124
124
  "local-invocations.mjs": "f6ac4c41c1a5ec34de358c4cca210ca8e403b3a913150a43bb55ec9be55d9998",
package/releases.json CHANGED
@@ -1,4 +1,10 @@
1
1
  [
2
+ {
3
+ "version": "0.1.32",
4
+ "date": "2026-10-11",
5
+ "zh": "增加云端沙箱状态与用量只读查询,并支持按任务直接读取真实状态。",
6
+ "en": "Added read-only cloud sandbox status and direct reads of authoritative task state and usage."
7
+ },
2
8
  {
3
9
  "version": "0.1.31",
4
10
  "date": "2026-10-11",