@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 +5 -0
- package/SKILL.md +5 -3
- package/cli.mjs +14 -2
- package/cloud-task-client.mjs +56 -0
- package/manifest.json +1 -1
- package/package.json +1 -1
- package/release-state.json +5 -5
- package/releases.json +6 -0
package/CHANGELOG.md
CHANGED
package/SKILL.md
CHANGED
|
@@ -5,7 +5,7 @@ description: An engineering skill that understands a task, chooses a fitting wor
|
|
|
5
5
|
|
|
6
6
|
# entrorove · 熵巡
|
|
7
7
|
|
|
8
|
-
Version: 0.1.
|
|
8
|
+
Version: 0.1.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
|
|
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))) {
|
package/cloud-task-client.mjs
CHANGED
|
@@ -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
package/package.json
CHANGED
package/release-state.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "entrorove.release-state/1.0",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"digest": "
|
|
3
|
+
"version": "0.1.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": "
|
|
47
|
+
"cli.mjs": "6d455d8e22fccd24332726de6821a8a99f628d057648c9aae7c6262d89745722",
|
|
48
48
|
"review-client.mjs": "3491eef68ed533174b31db3c53febb6519b8f088f71a9964644714a9a4c03c77",
|
|
49
49
|
"version.mjs": "1f392147d72c40af4b03b307ea607075fb815af5174fa07e254b95fe12dbf3e7",
|
|
50
|
-
"SKILL.md": "
|
|
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": "
|
|
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