@entrorove/skill 0.1.40 → 0.1.43
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 +15 -0
- package/DELIVERY-BOUNDARIES.md +30 -0
- package/IDE-EXECUTION.md +10 -2
- package/SKILL.md +10 -6
- package/cli.mjs +63 -77
- package/ide-code-mode.mjs +6 -0
- package/ide-command.mjs +13 -6
- package/ide-hook.mjs +37 -9
- package/ide-install.mjs +208 -35
- package/ide-session.mjs +37 -9
- package/install-cleanup.mjs +59 -0
- package/local-budget.mjs +2 -1
- package/local-contracts.mjs +9 -1
- package/local-discipline-repository.mjs +41 -7
- package/local-runner-discipline.mjs +7 -3
- package/local-stage-boundary.mjs +92 -0
- package/manifest.json +1 -1
- package/package.json +4 -1
- package/release-state.json +22 -19
- package/release.mjs +10 -2
- package/releases.json +18 -0
- package/remote-client.mjs +78 -1
- package/task-entry-client.mjs +4 -0
- package/workflow-local-contracts.mjs +2 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
// Delivery-boundary and stop-loss contract (额度可见性与可交付边界 · WP-C).
|
|
2
|
+
//
|
|
3
|
+
// A boundary is the only legal stopping point: it exists where the system is
|
|
4
|
+
// runnable, demonstrable and roll-backable. Stopping at a boundary yields the
|
|
5
|
+
// independent terminal status `delivered-stage-N`; it must never be reported as
|
|
6
|
+
// failed or blocked, and resuming continues at the next boundary without
|
|
7
|
+
// re-running delivered stages.
|
|
8
|
+
//
|
|
9
|
+
// Consumption is measured, never predicted: without an enforced budget there is
|
|
10
|
+
// no baseline, so the decision stays explicitly not-estimable instead of
|
|
11
|
+
// inventing a number.
|
|
12
|
+
const terminalPattern = /^delivered-stage-([1-9][0-9]{0,2})$/u;
|
|
13
|
+
export const STAGE_BOUNDARY_SCHEMA = 'entrorove.stage-boundary/1.0';
|
|
14
|
+
|
|
15
|
+
export function stageTerminal(count) {
|
|
16
|
+
if (!Number.isSafeInteger(count) || count < 1 || count > 999) throw new Error('A delivered stage count requires a positive bounded integer');
|
|
17
|
+
return `delivered-stage-${count}`;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function stageOf(status) {
|
|
21
|
+
const match = typeof status === 'string' ? terminalPattern.exec(status) : null;
|
|
22
|
+
return match ? Number(match[1]) : null;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function isStageTerminal(status) { return stageOf(status) !== null; }
|
|
26
|
+
|
|
27
|
+
export function stageMessage(status, remaining) {
|
|
28
|
+
const stage = stageOf(status);
|
|
29
|
+
if (stage === null) throw new Error('A delivered stage message requires a delivered terminal status');
|
|
30
|
+
if (!Number.isSafeInteger(remaining) || remaining < 0) throw new Error('Delivered stages require their remaining bounded count');
|
|
31
|
+
return remaining === 0
|
|
32
|
+
? `阶段 ${stage} 已交付,全部阶段完成。`
|
|
33
|
+
: `阶段 ${stage} 已交付,剩余 ${remaining} 个阶段待续跑;从下一个边界继续,不重新执行已交付阶段。`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function measuredMetering(metering) {
|
|
37
|
+
if (!metering || typeof metering !== 'object' || Array.isArray(metering)) throw new Error('Boundary metering requires the actual consumption view');
|
|
38
|
+
const { enforced, elapsedMs, maxDurationMs } = metering;
|
|
39
|
+
if (typeof enforced !== 'boolean') throw new Error('Boundary metering requires its enforcement flag');
|
|
40
|
+
if (!enforced) return null;
|
|
41
|
+
if (!Number.isSafeInteger(elapsedMs) || elapsedMs < 0 || !Number.isSafeInteger(maxDurationMs) || maxDurationMs < 1) {
|
|
42
|
+
throw new Error('Enforced boundary metering requires measured elapsed and bounded duration');
|
|
43
|
+
}
|
|
44
|
+
return { elapsedMs, maxDurationMs };
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// The decision is taken at a clean boundary: close here when the measured
|
|
48
|
+
// consumption of the stage just delivered reaches the configured share of the
|
|
49
|
+
// enforced budget, otherwise continue to the next boundary.
|
|
50
|
+
export function boundaryDecision(input) {
|
|
51
|
+
const { steps, deliveredSequence, metering, ratio = 0.8 } = input ?? {};
|
|
52
|
+
if (!Array.isArray(steps) || steps.length === 0 || steps.some(step => !step || !Number.isSafeInteger(step.sequence))) {
|
|
53
|
+
throw new Error('Boundary decision requires the accepted plan steps with their sequences');
|
|
54
|
+
}
|
|
55
|
+
if (!Number.isSafeInteger(deliveredSequence) || deliveredSequence < 0 || deliveredSequence >= steps.length) {
|
|
56
|
+
throw new Error('Boundary decision requires a delivered sequence inside the accepted plan');
|
|
57
|
+
}
|
|
58
|
+
if (typeof ratio !== 'number' || !(ratio > 0 && ratio <= 1)) throw new Error('Boundary threshold ratio must be inside (0,1]');
|
|
59
|
+
const remainingStages = steps.length - deliveredSequence;
|
|
60
|
+
const nextSequence = deliveredSequence + 1;
|
|
61
|
+
const measured = measuredMetering(metering);
|
|
62
|
+
if (!measured) {
|
|
63
|
+
return { schemaVersion: STAGE_BOUNDARY_SCHEMA, action: 'continue', status: null, nextSequence, remainingStages,
|
|
64
|
+
reason: 'not-estimable', basis: 'none', detail: '没有强制预算基线,不预估剩余量;继续到下一个边界。' };
|
|
65
|
+
}
|
|
66
|
+
const consumed = measured.elapsedMs / measured.maxDurationMs;
|
|
67
|
+
const reached = consumed >= ratio;
|
|
68
|
+
return { schemaVersion: STAGE_BOUNDARY_SCHEMA, action: reached ? 'close' : 'continue',
|
|
69
|
+
status: reached ? stageTerminal(deliveredSequence) : null, nextSequence, remainingStages,
|
|
70
|
+
reason: reached ? 'near-threshold' : 'below-threshold', basis: 'measured',
|
|
71
|
+
consumedMs: measured.elapsedMs, budgetMs: measured.maxDurationMs, ratio,
|
|
72
|
+
detail: reached ? '已消耗达到阈值的既定比例,在当前干净边界收口。' : '仍在阈值以内,继续到下一个边界。' };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Resuming starts at the first stage that was not delivered; delivered stages
|
|
76
|
+
// are never re-executed.
|
|
77
|
+
export function nextBoundary(steps, deliveredSequence) {
|
|
78
|
+
if (!Array.isArray(steps)) throw new Error('Resuming a boundary requires the accepted plan steps');
|
|
79
|
+
if (!Number.isSafeInteger(deliveredSequence) || deliveredSequence < 0) throw new Error('Resuming a boundary requires a delivered sequence');
|
|
80
|
+
return steps.find(step => step.sequence === deliveredSequence + 1) ?? null;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export function stageReport(status, steps) {
|
|
84
|
+
const delivered = stageOf(status);
|
|
85
|
+
if (delivered === null || !Array.isArray(steps)) throw new Error('A stage report requires a delivered terminal status and the accepted plan steps');
|
|
86
|
+
const next = nextBoundary(steps, delivered);
|
|
87
|
+
return { schemaVersion: STAGE_BOUNDARY_SCHEMA, status, deliveredStages: delivered, totalStages: steps.length,
|
|
88
|
+
remainingStages: Math.max(0, steps.length - delivered),
|
|
89
|
+
deliveredStepIds: steps.filter(step => step.sequence <= delivered).map(step => step.stepId ?? null),
|
|
90
|
+
nextStepId: next?.stepId ?? null, terminal: true,
|
|
91
|
+
message: stageMessage(status, Math.max(0, steps.length - delivered)) };
|
|
92
|
+
}
|
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.43",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"entrorove": "cli.mjs"
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"local-contracts.mjs",
|
|
15
15
|
"local-contract-types.mjs",
|
|
16
16
|
"local-state-lock.mjs",
|
|
17
|
+
"local-stage-boundary.mjs",
|
|
17
18
|
"local-execution.mjs",
|
|
18
19
|
"local-swarm-authority.mjs",
|
|
19
20
|
"local-swarm-baseline.mjs",
|
|
@@ -203,6 +204,7 @@
|
|
|
203
204
|
"ide-command.mjs",
|
|
204
205
|
"ide-hook.mjs",
|
|
205
206
|
"ide-install.mjs",
|
|
207
|
+
"install-cleanup.mjs",
|
|
206
208
|
"ide-session.mjs",
|
|
207
209
|
"break-glass.mjs",
|
|
208
210
|
"ide-results.mjs",
|
|
@@ -226,6 +228,7 @@
|
|
|
226
228
|
"runtime/validator-runtime-v7.0.44.d.mts",
|
|
227
229
|
"IDE-EXECUTION.md",
|
|
228
230
|
"REUSE-DISCIPLINE.md",
|
|
231
|
+
"DELIVERY-BOUNDARIES.md",
|
|
229
232
|
"reuse-discipline-release.mjs"
|
|
230
233
|
],
|
|
231
234
|
"scripts": {
|
package/release-state.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": "entrorove.release-state/1.0",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"digest": "
|
|
3
|
+
"version": "0.1.43",
|
|
4
|
+
"digest": "4def2226e316c684fd009096f1bcafeec0c3519a3d4532cebe203ef095834467",
|
|
5
5
|
"files": {
|
|
6
|
-
"ide-code-mode.mjs": "
|
|
7
|
-
"ide-command.mjs": "
|
|
8
|
-
"ide-hook.mjs": "
|
|
9
|
-
"ide-install.mjs": "
|
|
10
|
-
"ide-session.mjs": "
|
|
6
|
+
"ide-code-mode.mjs": "f3f53357ba09727b3b597851976a24de93287c0faca5052448277d0904bb61f7",
|
|
7
|
+
"ide-command.mjs": "158d8f26c1dc28a04284e429150a2060d7278661f656a75e7e9f7600f536b7bf",
|
|
8
|
+
"ide-hook.mjs": "a2f151a6d1651872b0160487493d3ecedf01e30301b7af3d336201e7f6135e32",
|
|
9
|
+
"ide-install.mjs": "10247efadcfeef5da001022d12080bd0f789e67fdf7862bcc65db73dda3bbe57",
|
|
10
|
+
"ide-session.mjs": "ce3ee463804faf4c557d82ff221b0bf7ddb6f6ab7257ce7e9e0af8fbc15d57b8",
|
|
11
11
|
"break-glass.mjs": "2ad6f084c788d63fec11e64412864ac715bcb1a282dd2d8f03dc14e89e82135e",
|
|
12
12
|
"ide-results.mjs": "dfe0d3f773c65a9fc21056538d7005012c982ed4509bc0410d7f62813d0863fd",
|
|
13
13
|
"ide-queue.mjs": "806e716c775fd0079417027b135977c8516f47dddb0bc5ca19e32a355dab0e9e",
|
|
@@ -19,9 +19,9 @@
|
|
|
19
19
|
"local-discipline-gate.mjs": "04b1ba092d7f4342a0e77cfbeb44d9634dbce9fec0c79e6a1e4b11a662d904ac",
|
|
20
20
|
"local-discipline-native.mjs": "8b99b5ce951cab3c1426428ad807650c61c0ffb2c346d747b73b99057b382049",
|
|
21
21
|
"local-discipline-operations.mjs": "9fcb7b8889b7718d42e1d37936485d8198d5017d405e0cdbbabdbbd12fcc9d48",
|
|
22
|
-
"local-discipline-repository.mjs": "
|
|
22
|
+
"local-discipline-repository.mjs": "d818aa6137459ef200892479cc8c47fe82c884dc0e76dc7e6d45a6b41a13c6ec",
|
|
23
23
|
"local-discipline-snapshot.mjs": "8fd35b2cfbece8f64579f144f589a66dec9b6022d50fe931c4c1f886cb83134d",
|
|
24
|
-
"local-runner-discipline.mjs": "
|
|
24
|
+
"local-runner-discipline.mjs": "86f451de2f1e12a24f5596a29828891c1eba13cd4714ed0c18a77d66cecef934",
|
|
25
25
|
"local-integrity.d.mts": "21357f306234bd841c0d3d90bf2d09f7663f63746f897b9f38190428ae8198b3",
|
|
26
26
|
"local-equivalence-runner.mjs": "df2f406c693c4da7bb30542ec7b4d46a9336f56e9fdd263196c0f3a73d2f6e91",
|
|
27
27
|
"validator-runtime-build.mjs": "da20bd19eb088d79d62e33969b4c075dc2199761b395e40060227f8f86b9519a",
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"runtime/validator-runtime-v7.0.44.d.mts": "7797edbfe2f7de24da370204dce4dfd22822a1bd80df93514fff900b98afe36f",
|
|
30
30
|
"snapshot-retention.mjs": "4f8919fe8ec49fb4c23e080a8ad2fa3a9282bca3fffe7cf55c64e89ef316697e",
|
|
31
31
|
"snapshot-cleanup-journal.mjs": "76a9684cc95b4eb076e1298d78a9dff37948b00d9607b8f546c599072d3ed331",
|
|
32
|
-
"IDE-EXECUTION.md": "
|
|
32
|
+
"IDE-EXECUTION.md": "64f48dd283f8b7ad76bd33b542baebc3ae4380315c4b7158974927fd4f7a4c17",
|
|
33
33
|
"REUSE-DISCIPLINE.md": "295ecd41c931b00c21d009ab65ac160f0e2ab81b4000ed498d2e8e97c2dc6c63",
|
|
34
34
|
"reuse-discipline-release.mjs": "20ded9c21bd71b8779c454f5eba4c7c0a943ef99d94117b9bbef891d2ab6e3de",
|
|
35
35
|
"local-final-gate16.mjs": "b30caab08441449ad556a6e9a3cefbf91190f0b3f7370f46d2a21156375aa8e3",
|
|
@@ -73,15 +73,17 @@
|
|
|
73
73
|
"local-autocoord17-waits.mjs": "2b0a713987822548a94e1ed3a9a891532db45383797dfc5d5bc8d1e35593cf25",
|
|
74
74
|
"local-validator-isolation17.mjs": "48e94604e28b8fddd567dfb35ff60b73fd094a5803bd49f076388b7f310f92aa",
|
|
75
75
|
"local-calctool-composition17.mjs": "ac89fcb41ab0d0d9b47c1b5696945281b0894eb064820775e36a011c76314e6a",
|
|
76
|
-
"cli.mjs": "
|
|
76
|
+
"cli.mjs": "14e27d25acf2838f3eddd24a21ec438baa82650ac2235fb471f15718e996109f",
|
|
77
|
+
"install-cleanup.mjs": "72bb6bd55382449a986828cd1ae3e98e5fd0bf373f89bbdcc039023ae72a2337",
|
|
77
78
|
"review-client.mjs": "3491eef68ed533174b31db3c53febb6519b8f088f71a9964644714a9a4c03c77",
|
|
78
79
|
"version.mjs": "1f392147d72c40af4b03b307ea607075fb815af5174fa07e254b95fe12dbf3e7",
|
|
79
|
-
"SKILL.md": "
|
|
80
|
+
"SKILL.md": "5531f764b82b3c2fe89592d291d05f508711b1498a65c75219c2b4396b532467",
|
|
80
81
|
"CAPABILITY-MAP.md": "a0f0468a098725ced52a96dd8e22bfc7d1ce7681a8446ebf7dae3696c76c3385",
|
|
81
82
|
"AGREEMENT.md": "f93a68e92c457200dd024610e65f74e478b8f60860f951da818b70561f1b9bf8",
|
|
82
|
-
"
|
|
83
|
+
"DELIVERY-BOUNDARIES.md": "d1bb2895e23fc14bf1c76707bd1f6f03b39695501a78a0b7289dc37b099889dc",
|
|
84
|
+
"package.json": "8be823b5756da9b393af966a4152bee301cb49f988823aaf757e8c51bf867085",
|
|
83
85
|
"manifest.json": "ab06e307795bc9da5add926752b6c4dbdaf18625090261a035aa356a679c504f",
|
|
84
|
-
"release.mjs": "
|
|
86
|
+
"release.mjs": "9b71dc6dbda1e8db1097f0b14dbc1d66b3968ed241813f32851ceef54facec77",
|
|
85
87
|
"local-cli.mjs": "aa4c217c5029408020f76d6c0c5dafc9a0f51216085b2624f3b6aca3cffbe555",
|
|
86
88
|
"local-state-lock.mjs": "1dbf64264642a0851faf043e07ee9f66d2ad0508e9f799b0626246e42fae893e",
|
|
87
89
|
"local-execution.mjs": "46fddd78cd954fb080c660affe90cdaa716695580427336acb820089441a8025",
|
|
@@ -114,8 +116,9 @@
|
|
|
114
116
|
"local-budget-source-bindings.mjs": "cfe97b257fd2da0dd45f95f5e45be20baa6445d11ac6d03538a0105b4985b8ff",
|
|
115
117
|
"local-budget-store.mjs": "2ae36c977ecd32d81f88e2eaa697ce8c228cb4405ecc5c4169cdda104c8ce138",
|
|
116
118
|
"local-budget-transition.mjs": "3894f05d4b5d4d6e16e3f201ff8902e6311cf6434010262934e0d1251aa8b9f0",
|
|
117
|
-
"local-budget.mjs": "
|
|
119
|
+
"local-budget.mjs": "857bf879addbfbc13bd95d0957b223e05e73a69b8092f1d1933f09ff7968659a",
|
|
118
120
|
"local-flow-lifecycle.mjs": "47534e16599002e5e7cf7d3e95195f4d7a364d2b651ec339d8c6c017d71c1b05",
|
|
121
|
+
"local-stage-boundary.mjs": "84c3bb5beab29306274c5ca8a78f19a83ed664ae1b93a8372bb493158b304fe3",
|
|
119
122
|
"local-scope-candidate.mjs": "8f0bd9606e70d4a0ebacdd3cd600ec3afed85e2bb3e1760aa1144cf55d4e028a",
|
|
120
123
|
"local-scope-context.mjs": "79753abfc6c76089d17f003a1be537dfaea10d6731c542f7fc53f2a9996ed164",
|
|
121
124
|
"local-scope-files.mjs": "96c301f2a45e5fa22f0b11fb15e5e564f118e53187fc7749263c78d5ed87b056",
|
|
@@ -149,7 +152,7 @@
|
|
|
149
152
|
"local-scope-state.mjs": "8b600a91fc0068d7a8c0bb752ddba7ed30ada93daafb118d6cba2368fd94cb27",
|
|
150
153
|
"local-scope-workspaces.mjs": "a44c34537e5ed2dcaf193a985e5bc05957989fbb160a650f9e37ba7d66eb2de8",
|
|
151
154
|
"local-task-routing.mjs": "6e2e506b2fb0e2e8d8c5147d7df32849b57a4e94a23634f01a355d45735858e4",
|
|
152
|
-
"remote-client.mjs": "
|
|
155
|
+
"remote-client.mjs": "8c2450613480d0bdb39e942fb1dea14d74d5ffadd3c72809c74aa5fbc3c8d773",
|
|
153
156
|
"cloud-task-client.mjs": "11acb1a033c94cdfbdfb177a3402ad97f6a5226f577138c8cf6395dc3ebb1a39",
|
|
154
157
|
"scope-runner-client.mjs": "646ab4f80d4a8209e922fd45f40efd968f0744d9dfc03188b222c1a2e11e83b8",
|
|
155
158
|
"native-client.mjs": "6f5575909bae9daba643287f876ffa0f9ff1c53a367b32a40145d740456d6605",
|
|
@@ -159,7 +162,7 @@
|
|
|
159
162
|
"cloud-event-stream.mjs": "e0eec9fc3e0613094523929634f25030df5ca5c5b5fe2c1e1a4586ab10574808",
|
|
160
163
|
"ide-presentation.mjs": "3bac21bfc824fcdad63aafb0d7c3326cd6456923f4224106dd5c38682060f315",
|
|
161
164
|
"automatic-feedback-client.mjs": "75e92f50d6fbfa4f482af36e16c9ce5dd323a02e99eb9b434dcfa3faa846a532",
|
|
162
|
-
"task-entry-client.mjs": "
|
|
165
|
+
"task-entry-client.mjs": "869f234402c4149eadf1ec138705fc140e2fa16b2a3ea5dc2b2f51dfb189d7de",
|
|
163
166
|
"task-identity.mjs": "e0e6cf1f48bfa5ee3c5cb86a3c21adfce6d66b4220f4a164ca099263c7a09fb4",
|
|
164
167
|
"task-identity.d.mts": "55472e1ffc81b9d5e5c5bd56c0bf1d18ecde03ee5170a58a15ce9caf222d8761",
|
|
165
168
|
"remote-transport.mjs": "93caaca646fca298a4e08142678b134ecc3a657e00de5b9939e2364b2db9d6c4",
|
|
@@ -177,12 +180,12 @@
|
|
|
177
180
|
"local-task-handoff-write-archive.mjs": "3668f39d8ab5664ed717994cf1b4bcc7ea23e146a0e06291f851d30337faeb77",
|
|
178
181
|
"local-task-handoff-write-receipts.mjs": "e1321127bd6fcad7840e185639f81ae68a8722a0ee4264a7b504a02b27887647",
|
|
179
182
|
"workflow-local-runner.mjs": "9fa899a11da2b6b7a436bf9b561641856adcbc5f8b914f6ba89a64dae224900d",
|
|
180
|
-
"workflow-local-contracts.mjs": "
|
|
183
|
+
"workflow-local-contracts.mjs": "bc52a461727b34c72daa058e1aa77d58206eafad14a93a347537f9969ae51184",
|
|
181
184
|
"workflow-local-client.mjs": "45c954f694d96bf0ea87ee2dc6902a6763dac2cb1df713b6a5e749632054e9af",
|
|
182
185
|
"workflow-local-request.mjs": "4e24c543ce386292a87dc9cd41f90d23375f12079cacffc515c8cd01fd571780",
|
|
183
186
|
"task-message-entry.mjs": "31d10056cb905237cd5649e8eb067009ff1612ec5dc1061e0373209fbc0b646a",
|
|
184
187
|
"task-message-cli.mjs": "3ca65e96c28129b3bd5cac962d106e0859a1f17df1f6a66ee543c6efc22f918d",
|
|
185
|
-
"local-contracts.mjs": "
|
|
188
|
+
"local-contracts.mjs": "bb1df682f06782f1c8814d50fe1c455153b29f3a1a093e87dd4ab2ed5ae16e1a",
|
|
186
189
|
"local-contract-types.mjs": "85e71fa4dd67e351a4b67573c740bcdb1661cede53f097189f11837771e75e91",
|
|
187
190
|
"local-archguard-ast.mjs": "7ff7df9dab0d98ed62983add751c80edea598bc94ef4f38ede0ebd4d41226c87",
|
|
188
191
|
"local-archguard-checkpoint.mjs": "37896902520cc995720c96288e4a5ed3585952b55c9c35be281f91fa754c71ec",
|
package/release.mjs
CHANGED
|
@@ -48,7 +48,7 @@ const sourceFiles = [
|
|
|
48
48
|
'local-merge-transaction.mjs',
|
|
49
49
|
...swarmSourceFiles,
|
|
50
50
|
...coordination17SourceFiles,
|
|
51
|
-
'cli.mjs', 'review-client.mjs', 'version.mjs', 'SKILL.md', 'CAPABILITY-MAP.md', 'AGREEMENT.md',
|
|
51
|
+
'cli.mjs', 'install-cleanup.mjs', 'review-client.mjs', 'version.mjs', 'SKILL.md', 'CAPABILITY-MAP.md', 'AGREEMENT.md', 'DELIVERY-BOUNDARIES.md',
|
|
52
52
|
'package.json', 'manifest.json', 'release.mjs',
|
|
53
53
|
'local-cli.mjs', 'local-state-lock.mjs', 'local-execution.mjs', 'local-integrity.mjs', 'local-evidence-verification.mjs', 'local-formula.mjs', 'local-ledger.mjs',
|
|
54
54
|
'local-error.mjs',
|
|
@@ -60,7 +60,7 @@ const sourceFiles = [
|
|
|
60
60
|
'local-budget-grants.mjs', 'local-budget-handoff.mjs', 'local-budget-handoff-contracts.mjs', 'local-budget-lock.mjs',
|
|
61
61
|
'local-budget-handoff-completion.mjs',
|
|
62
62
|
'local-budget-reads.mjs', 'local-budget-source-bindings.mjs', 'local-budget-store.mjs',
|
|
63
|
-
'local-budget-transition.mjs', 'local-budget.mjs', 'local-flow-lifecycle.mjs',
|
|
63
|
+
'local-budget-transition.mjs', 'local-budget.mjs', 'local-flow-lifecycle.mjs', 'local-stage-boundary.mjs',
|
|
64
64
|
'local-scope-candidate.mjs',
|
|
65
65
|
'local-scope-context.mjs',
|
|
66
66
|
'local-scope-files.mjs',
|
|
@@ -299,8 +299,10 @@ function releaseLabels() {
|
|
|
299
299
|
'archguard-runtime-build.mjs': { zh: 'Archguard 架构合同与执行守卫', en: 'Archguard architecture contract and execution guard' },
|
|
300
300
|
'runtime/archguard-runtime-v7.0.44.mjs': { zh: 'Archguard 架构合同与执行守卫', en: 'Archguard architecture contract and execution guard' },
|
|
301
301
|
'cli.mjs': { zh: '技能运行和受管安装', en: 'skill runtime and managed installation' },
|
|
302
|
+
'install-cleanup.mjs': { zh: '旧版受管安装清理', en: 'managed installation cleanup' },
|
|
302
303
|
'version.mjs': { zh: '版本安全检查', en: 'version safety checks' },
|
|
303
304
|
'SKILL.md': { zh: 'IDE 工作流程说明', en: 'IDE workflow instructions' },
|
|
305
|
+
'DELIVERY-BOUNDARIES.md': { zh: '任务交付边界说明', en: 'task delivery boundaries' },
|
|
304
306
|
'CAPABILITY-MAP.md': { zh: '能力覆盖映射', en: 'capability coverage map' },
|
|
305
307
|
'AGREEMENT.md': { zh: '使用、隐私与推广告知', en: 'usage, privacy, and promotion notice' },
|
|
306
308
|
'package.json': { zh: '安装包配置', en: 'package configuration' },
|
|
@@ -329,6 +331,7 @@ function releaseLabels() {
|
|
|
329
331
|
'local-budget-transition.mjs': { zh: '候选范围与正式范围预算转换', en: 'candidate and accepted scope budget transition' },
|
|
330
332
|
'local-budget.mjs': { zh: '本地三轴读取预算', en: 'local three-axis read budgets' },
|
|
331
333
|
'local-flow-lifecycle.mjs': { zh: 'Flow 终止与任务解绑', en: 'flow termination and task unbinding' },
|
|
334
|
+
'local-stage-boundary.mjs': { zh: '本地阶段边界与可恢复停止', en: 'local stage boundaries and recoverable stops' },
|
|
332
335
|
'local-probe.mjs': { zh: '范围探测与分档', en: 'scope probing and tiering' },
|
|
333
336
|
'local-scope-candidate.mjs': { zh: '临时接管范围独立验签', en: 'temporary takeover scope verification' },
|
|
334
337
|
'local-scope-context.mjs': { zh: '精确符号范围绑定', en: 'exact symbol scope binding' },
|
|
@@ -400,6 +403,11 @@ const metadata = JSON.parse(await read('package.json'))
|
|
|
400
403
|
const manifest = JSON.parse(await read('manifest.json'))
|
|
401
404
|
const state = JSON.parse(await read(stateFile))
|
|
402
405
|
const skill = await read('SKILL.md')
|
|
406
|
+
const generatedMetadata = new Set([stateFile, changelogFile, releasesFile])
|
|
407
|
+
const untrackedPackageFiles = metadata.files.filter(name => !generatedMetadata.has(name) && !sourceFiles.includes(name))
|
|
408
|
+
if (untrackedPackageFiles.length) {
|
|
409
|
+
throw new Error(`Packaged skill files lack release tracking: ${untrackedPackageFiles.join(', ')}`)
|
|
410
|
+
}
|
|
403
411
|
if (metadata.version !== manifest.version || metadata.version !== state.version
|
|
404
412
|
|| !skill.includes(`Version: ${metadata.version}.`)) {
|
|
405
413
|
throw new Error('Skill package, manifest, instruction, and release state versions differ')
|
package/releases.json
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
[
|
|
2
|
+
{
|
|
3
|
+
"version": "0.1.43",
|
|
4
|
+
"date": "2026-10-16",
|
|
5
|
+
"zh": "更新了Codex 后续轮次工具门禁、复用与变更一致性门禁、IDE 执行与复用纪律文档、技能运行和受管安装、旧版受管安装清理、IDE 工作流程说明、任务交付边界说明、安装包配置、自动版本与更新日志、本地三轴读取预算、本地阶段边界与可恢复停止、远端恢复客户端、账号沙箱偏好与任务入口确认、工作流本地调用契约。",
|
|
6
|
+
"en": "Updated Codex tool guards across turns, reuse and change consistency checks, IDE execution and reuse discipline documentation, skill runtime and managed installation, managed installation cleanup, IDE workflow instructions, task delivery boundaries, package configuration, automatic versioning and changelog, local three-axis read budgets, local stage boundaries and recoverable stops, remote recovery client, account sandbox preferences and task entry confirmation, workflow local invocation contracts."
|
|
7
|
+
},
|
|
8
|
+
{
|
|
9
|
+
"version": "0.1.42",
|
|
10
|
+
"date": "2026-10-16",
|
|
11
|
+
"zh": "修复受管钩子空文件恢复、旧安装清理及仓库控制快照误扫。",
|
|
12
|
+
"en": "Restored empty managed hook configs, cleaned old installations, and excluded control snapshots from semantic scanning."
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"version": "0.1.41",
|
|
16
|
+
"date": "2026-10-15",
|
|
17
|
+
"zh": "修复 0.1.39 受管技能升级与 Codex hook 配置权限误拒;补齐本地 probe/reassess 的 importContexts 输入合同。",
|
|
18
|
+
"en": "Fixed upgrades from the 0.1.39 managed skill and Codex hook config permission checks; added importContexts to local probe and reassess inputs."
|
|
19
|
+
},
|
|
2
20
|
{
|
|
3
21
|
"version": "0.1.40",
|
|
4
22
|
"date": "2026-10-15",
|
package/remote-client.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
+
import { pathToFileURL } from 'node:url';
|
|
2
3
|
import Ajv from 'ajv';
|
|
3
4
|
import { parseTransportResponse, requestTransport, trustedOrigin } from './remote-transport.mjs';
|
|
4
5
|
import { appendInvocation } from './local-invocations.mjs';
|
|
@@ -79,7 +80,8 @@ export async function invokeRemote(data, dependencies) {
|
|
|
79
80
|
if (['blocked','failed','incomplete'].includes(routed.status)) process.exitCode = 2;
|
|
80
81
|
return routed;
|
|
81
82
|
}
|
|
82
|
-
const
|
|
83
|
+
const resolvedApiOrigin = typeof apiOrigin === 'function' ? apiOrigin : () => new URL(apiUrl).origin;
|
|
84
|
+
const { response, result } = await invokeDiscovered(data, token, { home, apiOrigin: resolvedApiOrigin });
|
|
83
85
|
process.stdout.write(JSON.stringify(presentInvocationNotices(result,dependencies.onIdeEvent,{home})) + '\n');
|
|
84
86
|
if (!response.ok || result.output.status === 'blocked' || result.output.status === 'failed'
|
|
85
87
|
|| result.output.status === 'incomplete') process.exitCode = 2;
|
|
@@ -233,6 +235,81 @@ export async function queryStatus(requestId, dependencies) {
|
|
|
233
235
|
process.stdout.write(JSON.stringify(presentInvocationNotices(result,dependencies.onIdeEvent)) + '\n');
|
|
234
236
|
}
|
|
235
237
|
|
|
238
|
+
// Host quota (WP-D): a declared host adapter may report the host's own
|
|
239
|
+
// remaining quota. Without one, the answer is explicitly unknown and the
|
|
240
|
+
// skill keeps its own measured ledger only.
|
|
241
|
+
export async function hostQuotaView(environment = process.env) {
|
|
242
|
+
const declared = String(environment.ENTROROVE_IDE_ADAPTER ?? '').split(',').map(value => value.trim()).filter(Boolean);
|
|
243
|
+
for (const pathname of declared) {
|
|
244
|
+
let adapter;
|
|
245
|
+
try { const module = await import(pathToFileURL(pathname).href); adapter = module.default ?? module.adapter; }
|
|
246
|
+
catch { return { schemaVersion: 'entrorove.host-quota/1.0', state: 'unknown', reason: 'adapter-unavailable', detail: '宿主额度接口无法加载;只按 entrorove 这本账止损。' }; }
|
|
247
|
+
if (typeof adapter?.hostQuota !== 'function') continue;
|
|
248
|
+
let value;
|
|
249
|
+
try { value = await adapter.hostQuota(); }
|
|
250
|
+
catch { return { schemaVersion: 'entrorove.host-quota/1.0', state: 'unknown', reason: 'adapter-unavailable', detail: '宿主额度接口调用失败;只按 entrorove 这本账止损。' }; }
|
|
251
|
+
if (value && value.state === 'measured' && Number.isSafeInteger(value.remaining) && value.remaining >= 0) {
|
|
252
|
+
return { schemaVersion: 'entrorove.host-quota/1.0', state: 'measured', remaining: value.remaining, basis: 'host-reported' };
|
|
253
|
+
}
|
|
254
|
+
return { schemaVersion: 'entrorove.host-quota/1.0', state: 'unknown', reason: 'adapter-unavailable', detail: '宿主额度接口未返回可用测量值;只按 entrorove 这本账止损。' };
|
|
255
|
+
}
|
|
256
|
+
return { schemaVersion: 'entrorove.host-quota/1.0', state: 'unknown', reason: 'no-host-adapter', detail: '未接入宿主额度接口;只按 entrorove 这本账止损。' };
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
async function recurringCall(pathname, method, payload, dependencies, label) {
|
|
260
|
+
const token = await dependencies.readCredential(dependencies.home);
|
|
261
|
+
const response = await requestTransport(dependencies.apiOrigin(), pathname, { method,
|
|
262
|
+
headers: { authorization: `Bearer ${token}`, ...(payload ? { 'content-type': 'application/json' } : {}) },
|
|
263
|
+
...(payload ? { body: JSON.stringify(payload) } : {}) });
|
|
264
|
+
if (response.status === 204) return null;
|
|
265
|
+
const result = await readResponse(response, label);
|
|
266
|
+
if (!response.ok) throw new Error(`${label} failed: HTTP ${response.status}`);
|
|
267
|
+
return result;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
export async function listRecurring(dependencies) {
|
|
271
|
+
process.stdout.write(JSON.stringify(await recurringCall('/api/recurring', 'GET', null, dependencies, 'recurring list')) + '\n');
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
export async function claimRecurring(claimId, dependencies) {
|
|
275
|
+
const claimed = await recurringCall('/api/recurring/claim', 'POST', { claimId }, dependencies, 'recurring claim');
|
|
276
|
+
process.stdout.write(JSON.stringify(claimed ?? { claimed: false, detail: '当前没有到期的周期任务。' }) + '\n');
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
export async function finishRecurring(runId, input, dependencies) {
|
|
280
|
+
if (!/^[a-f0-9-]{36}$/u.test(runId)) throw new Error('finishing a recurring run requires its runId');
|
|
281
|
+
process.stdout.write(JSON.stringify(await recurringCall(`/api/recurring/runs/${runId}`, 'POST', input, dependencies, 'recurring finish')) + '\n');
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export async function readRecurringRuns(recurringId, dependencies) {
|
|
285
|
+
if (!/^[a-f0-9-]{36}$/u.test(recurringId)) throw new Error('recurring runs require the original recurringId');
|
|
286
|
+
process.stdout.write(JSON.stringify(await recurringCall(`/api/recurring/${recurringId}/runs`, 'GET', null, dependencies, 'recurring runs')) + '\n');
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
export async function queryBillingExport(dependencies) {
|
|
290
|
+
const token = await dependencies.readCredential(dependencies.home);
|
|
291
|
+
const response = await readOnlyGet(dependencies.apiOrigin(), '/api/skill/billing-export', { authorization: `Bearer ${token}` }, 'billing export');
|
|
292
|
+
const result = await readResponse(response, 'billing export');
|
|
293
|
+
if (response.status === 404) throw new Error('entrorove billing failed: HTTP 404; the reachable server does not expose /api/skill/billing-export yet (deploy the matching API version)');
|
|
294
|
+
if (!response.ok || result?.schemaVersion !== 'entrorove.billing-export/1.0') {
|
|
295
|
+
throw new Error(`entrorove billing failed: HTTP ${response.status}`);
|
|
296
|
+
}
|
|
297
|
+
process.stdout.write(JSON.stringify(result) + '\n');
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
export async function queryUsageSummary(flowId, dependencies) {
|
|
301
|
+
if (flowId !== undefined && !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/u.test(flowId)) throw new Error('usage requires an original flowId when given');
|
|
302
|
+
const path = flowId === undefined ? '/api/skill/usage-summary' : `/api/skill/usage-summary?flowId=${encodeURIComponent(flowId)}`;
|
|
303
|
+
const token = await dependencies.readCredential(dependencies.home);
|
|
304
|
+
const response = await readOnlyGet(dependencies.apiOrigin(), path, { authorization: `Bearer ${token}` }, 'usage summary');
|
|
305
|
+
const result = await readResponse(response, 'usage summary');
|
|
306
|
+
if (response.status === 404) throw new Error('entrorove usage failed: HTTP 404; the reachable server does not expose /api/skill/usage-summary yet (deploy the matching API version)');
|
|
307
|
+
if (!response.ok || result?.schemaVersion !== 'entrorove.usage-summary/1.0') {
|
|
308
|
+
throw new Error(`entrorove usage failed: HTTP ${response.status}`);
|
|
309
|
+
}
|
|
310
|
+
process.stdout.write(JSON.stringify({ ...result, hostQuota: await hostQuotaView(dependencies.environment) }) + '\n');
|
|
311
|
+
}
|
|
312
|
+
|
|
236
313
|
export async function queryFlows(dependencies) {
|
|
237
314
|
const token = await dependencies.readCredential(dependencies.home);
|
|
238
315
|
const response = await readOnlyGet(dependencies.apiOrigin(), '/api/skill/flows', { authorization: `Bearer ${token}` }, 'flow list')
|
package/task-entry-client.mjs
CHANGED
|
@@ -5,6 +5,10 @@ import { displayIdeEvent, ideClientHeaders, ideTaskIdentity } from './ide-presen
|
|
|
5
5
|
/** New IDE tasks use the authenticated account preference; resumes keep their original route. */
|
|
6
6
|
export async function routeTaskEntry(data, token, dependencies) {
|
|
7
7
|
if (data.operation !== 'start' || data.input?.sandboxTaskId) return null;
|
|
8
|
+
// Older embedders can invoke the remote client without the optional cloud
|
|
9
|
+
// sandbox preference callback. Keep those callers on the normal API path;
|
|
10
|
+
// production installs provide the callback and retain the preference gate.
|
|
11
|
+
if (typeof dependencies.apiOrigin !== 'function') return null;
|
|
8
12
|
const choice = data.sandboxChoice;
|
|
9
13
|
if (choice !== undefined && !['use','local'].includes(choice)) throw new Error('sandboxChoice must be use or local');
|
|
10
14
|
if (choice === 'local') {
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { array, enumeration, integer, ledgerIdentifier, object, relativePath, sha256 } from './local-contract-types.mjs';
|
|
2
|
+
import { DISCIPLINE_POLICY_SCHEMA } from './local-discipline-contracts.mjs';
|
|
2
3
|
|
|
3
4
|
const exact = properties => object(properties, Object.keys(properties));
|
|
4
5
|
const boundedArray = (items, minimum, maximum) => ({ ...array(items, minimum), maxItems: maximum });
|
|
@@ -17,6 +18,7 @@ const executionPolicy = exact({ executable: absolutePath, executableSha256: sha2
|
|
|
17
18
|
additionalProperties: { type: 'string', maxLength: 16_384, pattern: '^[^\\u0000]*$' } },
|
|
18
19
|
timeoutMs: integer(1, 300_000), maxOutputBytes: integer(1, 1024 * 1024), requiredExitCode: { const: 0 },
|
|
19
20
|
});
|
|
21
|
+
executionPolicy.properties.discipline = DISCIPLINE_POLICY_SCHEMA;
|
|
20
22
|
const baseline = exact({ schemaVersion: { const: 'validator.golden-baseline/1.0' }, baselineId: id,
|
|
21
23
|
source: exact({ kind: enumeration(['repository-commit', 'artifact', 'approved-record']), locator: shortText, digestSha256: sha256 }),
|
|
22
24
|
version: id, frozen: { const: true }, frozenAt: timestamp, frozenBy: id, testsSha256: sha256,
|