@entrorove/skill 0.1.61 → 0.1.62

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.62 — 2026-10-18
4
+
5
+ - 补齐本地新项目的受控创建与原生产步骤内迭代:原账号审批精确不存在路径和生产节点,S 与独立 M 签名校验真实基线,保留源文件只读保护、合同预算及失败历史。支持 PHP、JSON、原生模板、WXML、WXSS,通过实际创建、结算、测试和最终本地验收;钩子仍可关闭。
6
+ - Support governed creation and iteration of new local project files within their original producer and accepted plan. Bind exact absent paths and producers to owner approval, actual S and separate M evidence, protected sources, contract budgets and immutable failures. Cover PHP, JSON, native templates, WXML and WXSS through real writes, settlement, tests and final local acceptance while keeping hooks optional.
7
+
3
8
  ## 0.1.61 — 2026-10-18
4
9
 
5
10
  - 钩子改为可选:默认安装关闭钩子,IDE 可直接调用 SDK;只有明确选用技能的原会话与仓库启用拦截,普通查询、旧激活状态及无法归属的事件不再接管其他任务。保留账号、写入范围、签名和真实本地验收校验。
package/IDE-EXECUTION.md CHANGED
@@ -99,13 +99,17 @@ Computed runtime imports remain explicitly unresolved with their actual source p
99
99
 
100
100
  ### Restricted member editing
101
101
 
102
- When the accepted plan returns a `localAction` for `mutation-connect`, run `npx @entrorove/skill mutation-connect <original repositoryRoot>` with that action's JSON `input` on stdin. The input contains the original `taskId`, `flowId`, `stepId`, `leaseId`, `generation`, scope `runnerId` and exact `paths`. Use the same local home, account and scope signer. This route requires an accepted frozen modify policy and a live original lease; it does not create a second task or invoke a generic execution authority.
102
+ When the accepted plan returns a `localAction` for `mutation-connect`, run `npx @entrorove/skill mutation-connect <original repositoryRoot>` with that action's JSON `input` on stdin. The input contains the original `taskId`, `flowId`, `stepId`, `leaseId`, `generation`, scope `runnerId` and exact `paths`. Use the same local home, account and scope signer. This route requires the matching accepted frozen write policy and a live original lease; it does not create a second task or invoke a generic execution authority.
103
103
 
104
104
  The connector discovers the public cloud verification key through the authenticated official HTTPS capability endpoint and fixes it in private local storage. An explicit operator pin must match, and a changed key or origin is rejected rather than silently replaced. Subsequent local mutation calls load this public pin offline; discovery and `unlock` do not depend on that cache.
105
105
 
106
- The connector creates a separate local editing key, requests the cloud's original signed snapshot challenge, copies and verifies the actual files, signs their fresh observation, obtains a limited cloud pass and installs it. The local editing key differs from both the scope observation key and the independent validator key. It is stored privately outside the repository; no manual key configuration is required. An uncertain network result returns a structured blocked result with the original request ID. Reusing the identical connector input restores its saved stage through the original status GET and keeps its existing challenge and attestation; it never replaces an uncertain mutation POST.
106
+ The connector creates a separate local editing key, requests the cloud's original signed snapshot challenge, copies and verifies the actual files or their exact absence, signs their fresh observation, obtains a limited cloud pass and installs it. The local editing key differs from both the scope observation key and the independent validator key. It is stored privately outside the repository; no manual key configuration is required. An uncertain network result returns a structured blocked result with the original request ID. Reusing the identical connector input restores its saved stage through the original status GET and keeps its existing challenge and attestation; it never replaces an uncertain mutation POST.
107
107
 
108
- Use the returned `gatePassPath` with the discovered `local guarded-write` contract and preserve its exact flow, step and repository. Only existing declared modify targets are eligible. Runtime loader sources and observed project configuration stay protected by their original hashes and physical file identity. The local preflight rejects changed imports, removed definitions, public contract changes, new unknown dependencies and unsupported source formats. Unknown dependency coverage remains unknown after an eligible edit.
108
+ Use the returned `gatePassPath` with the discovered `local guarded-write` contract and preserve its exact flow, step and repository. A `preserved-existing-modify` pass covers only existing declared modify targets. Runtime loader sources and observed project configuration stay protected by their original hashes and physical file identity. That route's local preflight rejects changed imports, removed definitions, public contract changes, new unknown dependencies and unsupported source formats. Unknown dependency coverage remains unknown after an eligible edit.
109
+
110
+ New project files use a separate explicit role, including PHP, JSON, native templates, WXML and WXSS. Before freezing the plan, read `workflow-scope-status`, then submit the complete `workflow-scope-review` file map. Keep existing references as `read-only` with their real hashes. Each absent output uses `access: create`, its exact `producerNodeRef`, original `requirementRefs`, a concrete `reason`, and `sha256: SHA256("entrorove.missing-file/1.0")`. This hash represents real absence, never future contents. The original contract must already allow new files at those paths. Obtain the original owner's exact server-issued approval and run `scope-amend` with its proposal identity and original S signer. Do not create placeholders, change the original gate or start a replacement flow. Existing references or dependencies cannot be relabeled as creations. Exact output slots have a bounded role count; they do not expand existing-source read quotas, token limits or the original changed-line contract.
111
+
112
+ Bind the accepted `scopeRevisionDigest` in `workflow-plan`. The producer manifest contains each output with that absent baseline and a matching `discipline.writes` entry of `kind: create`. Only its original compiled producer may write it. Descendants may include the output read-only after that producer's actual local acceptance; actual hashes come from the immutable M settlement chain. Do not put unrelated or future outputs in an earlier step's input manifest. `mutation-connect` returns a `planned-file-create` pass only after S and M prove absence; guarded creation is exclusive and cannot overwrite an existing file or follow a symlink ancestor. After creation, refresh S, settle M and run the actual frozen tests as below. A further pass may return `planned-file-modify` only for files proven created by that same original producer and accepted plan, with its current authorized lease and actual settled baseline. This permits local development of those new outputs without weakening the protected existing-file modify route. Requirement, reuse, deletion, contract, scope, signature and repository checks still apply; unresolved dependencies remain unresolved.
109
113
 
110
114
  After the pass's actual writes finish, follow its scope refresh action: an amended scope uses `scope-amend` with the original stored `gatePassPath`; an unchanged original scope uses its complete original `scope-connect` input, including `importContexts`. Run `npx @entrorove/skill mutation-settle <original repositoryRoot>` with `{taskId,flowId,stepId,gatePassPath}`. The local M signer observes the real completed consumption, and the service requires a fresh S scan captured after those writes. This settlement preserves both before and after hashes, unchanged modes, pass nonces and the original lease. It never creates an architecture verification event. Further edits use the returned `localAction`, whose `previousPassId` identifies that exact settled pass; do not resend an already consumed write.
111
115
 
package/SKILL.md CHANGED
@@ -5,7 +5,7 @@ description: Execute a task selected for Entrorove through explicit SDK operatio
5
5
 
6
6
  # entrorove · 熵巡
7
7
 
8
- Version: 0.1.61.
8
+ Version: 0.1.62.
9
9
 
10
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
 
@@ -17,7 +17,8 @@ function declaredWrite(input, pass, baseline) {
17
17
  if (!planned || canonical(planned) !== canonical(supplied)) needs('Write declaration must match the original cloud-signed execution plan');
18
18
  }
19
19
  if (planned && !['modify', 'create', 'format'].includes(planned.kind)) needs('The declared physical action must use its matching guarded entry point');
20
- if (planned && planned.kind !== 'format' && planned.kind !== expectedKind) needs('Declared write kind differs from the actual snapshot baseline');
20
+ const development = pass.writeDelegation?.purpose === 'planned-file-modify' && baseline.exists && planned?.kind === 'create';
21
+ if (planned && planned.kind !== 'format' && planned.kind !== expectedKind && !development) needs('Declared write kind differs from the actual snapshot baseline');
21
22
  return planned;
22
23
  }
23
24
  function requireException(intent, kind, message) {
@@ -75,7 +76,9 @@ export async function disciplineWritePreflight(input, value, content) {
75
76
  await assertDisciplineRepository(input, binding.root, review, ledger);
76
77
  const intent = declaredWrite(input, pass, baseline);
77
78
  const original = baseline.exists ? (await readSnapshotCopy14(input, snapshot.snapshotRoot, snapshot.manifest, target)).content.toString('utf8') : '';
78
- if (pass.writeDelegation) assertDelegatedSourceModification({ path: target, before: original, after: content });
79
+ if (pass.writeDelegation?.purpose === 'planned-file-create') {
80
+ if (baseline.exists || intent?.kind !== 'create' || !pass.newFilePaths.includes(target)) needs('Planned creation cannot overwrite an existing source or replace its create role');
81
+ } else if (pass.writeDelegation?.purpose === 'preserved-existing-modify') assertDelegatedSourceModification({ path: target, before: original, after: content });
79
82
  const candidate = await disciplineRepositoryObservation(input, binding.root, { analyze: true, overrides: new Map([[target, content]]) });
80
83
  const removed = checkRemoved(review, candidate.analysis, target, intent, snapshot.manifest.disciplineReviewDigest, input.declaration);
81
84
  checkContracts(review, candidate.analysis, target, intent);
@@ -28,15 +28,17 @@ async function actualWrites(input, state) {
28
28
  const snapshot = await snapshotAuthority14(input, binding.root, pass.snapshotReceipt);
29
29
  if (sha256(canonical(snapshot.manifest)) !== pass.snapshotManifestDigest || snapshot.manifest.snapshotDigest !== pass.snapshotDigest) fail();
30
30
  const writes = [];
31
+ const create = pass.writeDelegation.purpose === 'planned-file-create';
31
32
  for (const target of pass.paths) {
32
33
  const completed = ledger.writes[target], before = snapshot.manifest.files.find(file => file.path === target);
33
34
  if (!iso(completed.writtenAt)) mutationFail14('ENTROROVE_MUTATION_CONSUMPTION_WRITE_TIME', 'Original write has no verifiable completion timestamp; its old receipt cannot authorize another mutation');
34
- if (!before?.exists || completed.kind && completed.kind !== 'modify' || !iso(completed.at)
35
+ if (!before || (create ? before.exists !== false || before.mode !== null : !before.exists)
36
+ || completed.kind && completed.kind !== 'modify' || !iso(completed.at)
35
37
  || Date.parse(completed.writtenAt) < Date.parse(pass.issuedAt) || Date.parse(completed.writtenAt) >= Date.parse(pass.expiresAt)
36
38
  || Date.parse(completed.writtenAt) < Date.parse(completed.at) || Date.parse(completed.writtenAt) > Date.now()) fail();
37
39
  const current = await mutationRead14(input, binding.root, target), copy = await readSnapshotCopy14(input, snapshot.snapshotRoot, snapshot.manifest, target);
38
- if (current.sha256 !== completed.contentDigest || current.mode !== completed.mode || current.mode !== before.mode) fail();
39
- assertDelegatedSourceModification({ path: target, before: copy.content.toString('utf8'), after: current.content.toString('utf8') });
40
+ if (current.sha256 !== completed.contentDigest || current.mode !== completed.mode || current.mode !== (create ? 0o644 : before.mode)) fail();
41
+ if (pass.writeDelegation.purpose === 'preserved-existing-modify') assertDelegatedSourceModification({ path: target, before: copy.content.toString('utf8'), after: current.content.toString('utf8') });
40
42
  writes.push({ path: target, beforeSha256: before.sha256, beforeMode: before.mode,
41
43
  afterSha256: current.sha256, afterMode: current.mode, writtenAt: completed.writtenAt });
42
44
  }
@@ -45,7 +47,7 @@ async function actualWrites(input, state) {
45
47
  return writes;
46
48
  }
47
49
  function receiptCore(pass, writes) {
48
- return { schemaVersion: 'entrorove.preserved-mutation-consumption/1.0', purpose: 'preserved-existing-modify-consumption',
50
+ return { schemaVersion: 'entrorove.preserved-mutation-consumption/1.0', purpose: `${pass.writeDelegation.purpose}-consumption`,
49
51
  keyId: pass.writeDelegation.mutationKeyId, ownerId: pass.ownerId, taskId: pass.taskId, flowId: pass.flowId, stepId: pass.stepId,
50
52
  leaseId: pass.leaseId, generation: pass.generation, epoch: pass.epoch, passId: pass.passId, passDigest: sha256(canonical(pass)),
51
53
  challengeId: pass.challengeId, challengeNonce: pass.challengeNonce, passNonce: pass.nonce,
@@ -114,7 +114,8 @@ export function mutationPass14(value, options) {
114
114
  if (pass.disciplinePolicy) disciplineApprovedPolicy(pass.disciplinePolicy);
115
115
  if (pass.writeDelegation && (!pass.disciplinePolicy || pass.parallelPaths || pass.disciplinePolicy.dataOperations?.length
116
116
  || pass.paths.some(target => { const write = pass.disciplinePolicy.writes.find(item => item.targetPath === target);
117
- return !write || write.kind !== 'modify' || write.deletedSymbols?.length || write.exceptions?.length; }))) {
117
+ return !write || write.kind !== (pass.writeDelegation.purpose !== 'preserved-existing-modify' ? 'create' : 'modify')
118
+ || write.deletedSymbols?.length || write.exceptions?.length; }))) {
118
119
  mutationFail14('ENTROROVE_MUTATION_DELEGATION_INVALID', 'Preserved mutation permits only the exact existing modification policy');
119
120
  }
120
121
  if (pass.parallelPaths && !validatorParallelDeclarationsValid(pass.parallelPaths)) mutationFail14('ENTROROVE_MUTATION_AUTHORITY_INVALID', 'Parallel paths must match the frozen equivalence contract');
@@ -25,7 +25,14 @@ export async function capturePreservedMutationProtection(input, root, authority,
25
25
  const delegation = preservedMutationDelegation(authority), review = await readDisciplineSnapshot(snapshot);
26
26
  for (const expected of delegation.targetFiles) {
27
27
  const file = snapshot.manifest.files.find(item => item.path === expected.path);
28
+ if (delegation.purpose === 'planned-file-create') {
29
+ if (!file || file.exists !== false || file.sha256 !== expected.sha256 || file.mode !== null) {
30
+ preservedMutationFail('Planned creation requires an actual absent target in the original M snapshot');
31
+ }
32
+ continue;
33
+ }
28
34
  if (!file?.exists || file.sha256 !== expected.sha256) preservedMutationFail('Preserved mutation target must retain its exact existing gate baseline');
35
+ if (delegation.purpose === 'planned-file-modify') continue;
29
36
  const imports = await scopeCandidateImports(root, { path: expected.path,
30
37
  content: (await scopeRead(root, expected.path, input)).content.toString('utf8') }, input);
31
38
  const declared = delegation.targetImports.find(item => item.path === expected.path);
@@ -35,7 +42,7 @@ export async function capturePreservedMutationProtection(input, root, authority,
35
42
  }
36
43
  }
37
44
  const unknown = review.analysis.unresolved.find(item => authority.paths.includes(item.path) && /(?:^import-|dynamic-import|dynamic-reference)/.test(item.reason));
38
- if (unknown) unknownTarget(unknown.path, unknown);
45
+ if (unknown && delegation.purpose === 'preserved-existing-modify') unknownTarget(unknown.path, unknown);
39
46
  const result = [];
40
47
  for (const expected of delegation.protectedFiles) result.push(await observe(input, root, expected));
41
48
  return result;
@@ -37,14 +37,18 @@ export function preservedMutationDelegation(authority) {
37
37
  || !local && authority.runnerKeyId === authority.authorityReceipt?.keyId) {
38
38
  preservedMutationFail('Preserved mutation cannot promote scope, mutation or workflow signing keys to independent validation');
39
39
  }
40
- if (value.schemaVersion !== 'entrorove.preserved-write-delegation/1.0' || value.purpose !== 'preserved-existing-modify'
40
+ const create = value.purpose === 'planned-file-create';
41
+ if (value.schemaVersion !== 'entrorove.preserved-write-delegation/1.0' || !['preserved-existing-modify', 'planned-file-create', 'planned-file-modify'].includes(value.purpose)
41
42
  || ['scopeKeyId', 'mutationKeyId', 'gateEvidenceDigest', 'importGraphDigest'].some(field => !/^[0-9a-f]{64}$/.test(value[field]))
42
43
  || publicKey.keyId !== value.mutationKeyId || new Set(roleKeys).size !== roleKeys.length
43
- || authority.epoch !== 0 || authority.newFilePaths.length !== 0) preservedMutationFail('Preserved mutation role or original epoch is invalid');
44
+ || authority.epoch !== 0 || (create ? canonical(authority.newFilePaths) !== canonical(authority.paths)
45
+ || value.targetFiles.some(file => file.sha256 !== sha256('entrorove.missing-file/1.0'))
46
+ : authority.newFilePaths.length !== 0)) preservedMutationFail('Preserved mutation role or original epoch is invalid');
44
47
  files(value.protectedFiles); files(value.targetFiles);
45
48
  if (canonical(value.targetFiles.map(file => file.path)) !== canonical(authority.paths)
46
49
  || value.protectedFiles.some(file => authority.paths.includes(file.path))
47
- || !Array.isArray(value.targetImports) || canonical(value.targetImports.map(file => file?.path)) !== canonical(authority.paths)) {
50
+ || !Array.isArray(value.targetImports) || (value.purpose !== 'preserved-existing-modify' ? value.targetImports.length !== 0
51
+ : canonical(value.targetImports.map(file => file?.path)) !== canonical(authority.paths))) {
48
52
  preservedMutationFail('Preserved mutation must retain its exact existing target and protected path sets');
49
53
  }
50
54
  for (const file of value.targetImports) {
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.61",
4
+ "version": "0.1.62",
5
5
  "endpoint": "https://entrorove.com",
6
6
  "requestSchemaVersion": "entrorove.skill.request/2.0",
7
7
  "supportedRequestSchemaVersions": [
@@ -103,7 +103,7 @@ async function remote(stage, operation, input, state, location, dependencies) {
103
103
  function challengeBinding(challenge, identity, mutator, options) {
104
104
  mutationChallenge14(challenge, options);
105
105
  if ([...fields, 'previousPassId'].some(field => canonical(challenge[field]) !== canonical(identity[field])) || challenge.repositoryDigest !== sha256(identity.repositoryRoot).slice(0, 32)
106
- || challenge.newFilePaths.length || !challenge.writeDelegation
106
+ || !challenge.writeDelegation
107
107
  || challenge.writeDelegation.mutationKeyId !== mutator.mutationKeyId || challenge.writeDelegation.mutationPublicKey !== mutator.mutationPublicKey) {
108
108
  fail('Mutation challenge must retain the original task, lease, physical repository, paths and separate M signer');
109
109
  }
@@ -193,7 +193,7 @@ async function connect(identity, local, mutator, location, dependencies) {
193
193
  function connected(identity, state) {
194
194
  return { schemaVersion: 'entrorove.mutation-connection/1.0', status: 'succeeded', taskId: identity.taskId,
195
195
  flowId: identity.flowId, stepId: identity.stepId, gatePassPath: state.gatePassPath, pass: state.issued.pass,
196
- purpose: 'preserved-existing-modify', grantsExecutionAuthority: false, grantsValidatorAuthority: false,
196
+ purpose: state.issued.pass.writeDelegation.purpose, grantsExecutionAuthority: false, grantsValidatorAuthority: false,
197
197
  ...(state.feedback ? { feedback: state.feedback } : {}) };
198
198
  }
199
199
  export async function connectMutation(repositoryRoot, input, dependencies) {
@@ -203,7 +203,7 @@ export async function connectMutation(repositoryRoot, input, dependencies) {
203
203
  local.repositoryRoot = location.root;
204
204
  for (const relative of original.paths) {
205
205
  const target = await mutationTarget14(location.root, relative, true);
206
- if (!target.exists || !target.stat.isFile()) fail('Mutation connection permits only concrete existing files');
206
+ if (target.exists && !target.stat.isFile()) fail('Mutation connection permits only an absent approved creation or a concrete existing file');
207
207
  }
208
208
  await bootstrapCloudMutationAuthority(dependencies);
209
209
  const mutator = await preparePreservedMutationSigner(local);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@entrorove/skill",
3
- "version": "0.1.61",
3
+ "version": "0.1.62",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "entrorove": "cli.mjs"
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "schemaVersion": "entrorove.release-state/1.0",
3
- "version": "0.1.61",
4
- "digest": "8211a23e233808dfc8f43dd0b28af5eae9b8bea5127b9550da8e8c50d9447052",
3
+ "version": "0.1.62",
4
+ "digest": "98f3367ea7253d0aa7e37473c9151a9dcf4308615ccb146b8da14603f3d1fe86",
5
5
  "files": {
6
6
  "connected-cli.mjs": "79c3359303957a9ebb8987e3dfb181f189d380fa02ef4462683b786aedfc7802",
7
7
  "local-approved-process.mjs": "442856df788e63f38757439ba0657d1c689aaf797631a955fae3dd639e844e6d",
8
8
  "local-approved-supervisor.mjs": "87142a4c13d27c8265cc1fd7fc9088988da9bbb02134164e1a7c5417da926ac7",
9
- "local-mutation-consumption.mjs": "cd8650b9be894639ceb35af88d23c8002b4acff27afad2e64174eb21a9424cfb",
9
+ "local-mutation-consumption.mjs": "13479c8ac1e711bce4be407f24d294372e6d45afbc66c5ae8a8a694cb937b713",
10
10
  "workflow-local-acceptance.mjs": "743ae19c1edff473af2596c7356ddff3892ff9acfb3bcaa660b662eacba463a8",
11
11
  "workflow-observation-client.mjs": "4ad34e5a467954ad1943a0f003e07dd6c4fb919d197ae9175a8b0c9b6e2aff32",
12
12
  "workflow-observation-connection.mjs": "00e887c1430b13fc49c3f51ae814edb7a05c6d61ed7091262ae91a0706fad084",
@@ -14,12 +14,12 @@
14
14
  "workflow-observation-runner.mjs": "3eb8280ec7abffcb30398e3f4e5f7d0ec3df4385fa720f188ed83757b87cd977",
15
15
  "workflow-observation-state.mjs": "a525046df9b3de75b10d2bf35c2b6d7719f12a647e4aee1f1e85dbdbfb167321",
16
16
  "workflow-observation-wire.mjs": "90047ca4fe028e4931406ff26d4fe871bcafb28a59c456795aae4f5c4b739e43",
17
- "local-preserved-mutation-protection.mjs": "95041d4f75253a153c7fd85573ba0457513ffe47a6a6bd00c4f59379b81ce580",
17
+ "local-preserved-mutation-protection.mjs": "5186a2f682e66c6828d1504ee074554cbae0fda58a5f446fbadfb868e1682dae",
18
18
  "local-preserved-mutation-signer.mjs": "2b0771cbdd18ba00267aa441b7892cd04feab9f8543ae5e2703430b1e580747f",
19
19
  "local-preserved-mutation-state.mjs": "337a172b2d0a03b0d5a89b8483afdd9a043a4999fe38f87679633c98c450126b",
20
- "local-preserved-mutation-wire.mjs": "2f2f623e768d49af59dbb9bb8245627cb7e72184e5a5d3239d91f395152cf9bf",
20
+ "local-preserved-mutation-wire.mjs": "6768ce5713d70f7c0bd05f2286bc4b32cd9b8bb1d3c8b9cc7a451cb9b176824d",
21
21
  "local-delegated-modify-analysis.mjs": "f87148ddb023b79e241ca97db582991da8d0e1a51b26b1d9bc2799a76efd7297",
22
- "mutation-client.mjs": "6455c35b483d6d22e42e7be708630db07d9fd1d3cdf639294b126b69db2eae2f",
22
+ "mutation-client.mjs": "62f8de10fedac4d4dacc7c738290095fcb4c0605c2b82b3a72500199dc1dffb9",
23
23
  "cloud-mutation-authority.mjs": "c7226e882a4f3be4d2f55728f515d5a815c0aa1f21aa5e4689314e6e6a8c66a2",
24
24
  "ide-code-mode.mjs": "f8ba4de33632ab4c6df52dab52f392414b4632c7e94b218b8065677970c075c7",
25
25
  "ide-command.mjs": "dbdb4cbf8e870c93a746ca176cbbdeffc0458de1293583d3eb9af4c256541370",
@@ -37,7 +37,7 @@
37
37
  "local-scope-import-expressions.mjs": "20f1e065582c68d2334e0dfaa130a559ff19886a57f9038dc569f65993bb06c8",
38
38
  "local-discipline-contracts.mjs": "ab0c11dcc4a6ffd3cb79b53862c19308eaf0d159deee7f9958266852d977363e",
39
39
  "local-discipline-contracts.d.mts": "defc684c78dc88afa1c54340ab4a01ae36db7aa11257cbe1f5cd323f608c78c4",
40
- "local-discipline-gate.mjs": "e3851157bf1d8bc86eb44212a88acd20acfc2d1152e7d87af6dc2a37afffcd6f",
40
+ "local-discipline-gate.mjs": "1d83bf32fde0d8f5ad1e4659f7edcb2797b1f4c9aee3ae548dad9d9447df3849",
41
41
  "local-discipline-native.mjs": "8b99b5ce951cab3c1426428ad807650c61c0ffb2c346d747b73b99057b382049",
42
42
  "local-discipline-operations.mjs": "9fcb7b8889b7718d42e1d37936485d8198d5017d405e0cdbbabdbbd12fcc9d48",
43
43
  "local-discipline-repository.mjs": "b6392e02ecae333dfdc8df41f203fd69bed035d88b15b16d112ab1897b3c297c",
@@ -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": "203aa4ae47cc45915e1a89bd7fbb56bf57aebccef444599b3a2d1d2816f01907",
53
+ "IDE-EXECUTION.md": "65ccbed8bba6e9e60a2fee2276cbde19053aa6909d9bd1415d5b5f9ee3baccec",
54
54
  "REUSE-DISCIPLINE.md": "5b214cf313e7f715f52d54e28093a2d038f0f196ca64b15d1c49587b9d8eecf8",
55
55
  "reuse-discipline-release.mjs": "7f55ae10ec3396ed3bc5430a0c64f94c33c2dfbc57b32084caab92fd5fd1586f",
56
56
  "local-final-gate16.mjs": "083aec470670e6cdb7ad2ab27b7a51b53a9ec3a8b4121cb9cbfa17d9940892c2",
@@ -106,7 +106,7 @@
106
106
  "DELIVERY-BOUNDARIES.md": "9b9db50ed1bcce9e77ff6527b6bb7eaf12f3b913162ea9cb7fe90db06b393a4f",
107
107
  "package.json": "ce0f78910ec9aeb36a7d61a30a68c6b117c9b29ca34cc8446a46604b251c131e",
108
108
  "manifest.json": "ab06e307795bc9da5add926752b6c4dbdaf18625090261a035aa356a679c504f",
109
- "release.mjs": "90e4c5beb05e263c2cacf09c476480ac3599a965d62e0adda68226a8baaa968c",
109
+ "release.mjs": "996681f5a85cfbf195646d99463d63202ad55ec821fe072893ae460f5edcfeef",
110
110
  "local-cli.mjs": "41e2a737c8587cb5ce469a7661f6d14b5ea4cd073f8286822fc4dc96b67f56a1",
111
111
  "local-state-lock.mjs": "1dbf64264642a0851faf043e07ee9f66d2ad0508e9f799b0626246e42fae893e",
112
112
  "local-execution.mjs": "185f34e917440a360b3c4bafd3af245243807d964ae3820b3cffaaa2e6348cc6",
@@ -183,10 +183,10 @@
183
183
  "scope-runner-client.mjs": "2afcbb8bc8a26d03f26787cb2ffd9994c4377757d16d54aa0c83752a29e833ea",
184
184
  "scope-amendment-client.mjs": "2161daaee131cc209d7ab75cde91a920cbca98153e7e7fd058ba5aacdf6789a3",
185
185
  "scope-amendment-state.mjs": "045375115cdca8c265f1bfd14d5cb052fcd24a97c5cc1e50a44a6f6725319698",
186
- "scope-amendment-wire.mjs": "bc4c80fda3154b7151006f7bed6cc0884050868e7ba936309b6516ed5c20512f",
186
+ "scope-amendment-wire.mjs": "3c4823e23bbdf330616bb675f07f9fcad7423266bd50b92e1134d226060e9b83",
187
187
  "scope-amendment-remote.mjs": "e73bc3e67b8adb663d679cdcc46f0f1a18529d0bf14dd1f6cdf21ad87ead7c71",
188
- "scope-amendment-observer.mjs": "6c0539e4ac0f738939a169826400d822d68c1e70ca2d87a9fe10a26945158770",
189
- "scope-amendment-mutation.mjs": "9b120b60aef4d04790a75d599595c5251649b843996f66ebe02e9ac40ffb99b2",
188
+ "scope-amendment-observer.mjs": "f078654b857b84ef4454c9cb56450b7cabd19ff5581fe06b23da4346cf609018",
189
+ "scope-amendment-mutation.mjs": "6becec3829c6c701f439dc8dc74d77b1d6c4a751386af436a8cf74b0554f8fdd",
190
190
  "scope-amendment-reference.mjs": "0537e53a1bea4b695f4804c5051261778c88f05b1ae4aff86c709dcfe83aa148",
191
191
  "native-client.mjs": "6f5575909bae9daba643287f876ffa0f9ff1c53a367b32a40145d740456d6605",
192
192
  "native-notification.mjs": "8859a26c6f13d222711f763acf49ed8546b3306cf71f990643ac31a5ccaf1ba1",
@@ -248,7 +248,7 @@
248
248
  "local-mutation-files.mjs": "087b00e8424a135e783eb432271012a71e55eeb4a5e30119490d1bc0b2160320",
249
249
  "local-mutation-snapshot.mjs": "f9077539680fb8d3ff33a962657756a8fe6afa8409b6191334509534216ebfe8",
250
250
  "local-mutation-audit.mjs": "5a30ee3446f632e032ffcfe46bcd97d6dfc0f099a76ea5185c3f9a9118c4f6cb",
251
- "local-mutation-wire.mjs": "fe251b3112d2394c5a0ab108f067ec17fb8569db7be9b3ceb86fab25c68e98e9",
251
+ "local-mutation-wire.mjs": "fe6adbbdd63a676f62996988995a5f53b08b1a2b79fd5d097a19bcd886ea3ea0",
252
252
  "local-mutation-binding.mjs": "4440d792453a07a375b635fa5a91db607e58162824baced5c79a9a513f4ec918",
253
253
  "local-mutation-pass-store.mjs": "1edc5fcc537dfa04b8ae8b07af554d61ea5911a5da281423ad57214ccf753ad4",
254
254
  "local-mutation-authority.mjs": "e6b79430ee6b5eb28173843a5faaf1c277da1e5ca7c1dcbd6d96cd60c4460c59",
package/release.mjs CHANGED
@@ -295,10 +295,6 @@ const taskEntryReleaseLabels = {
295
295
  }
296
296
 
297
297
  function releaseNote(changed) {
298
- if (changed.some(file => file.startsWith('scope-amendment-'))) return {
299
- zh: '新增同一任务的精确范围补正:原账号审核文件哈希与写入/只读角色,原S签名真实事实并重评原合同;计划、写入和结算绑定不可变范围修订,改后刷新保留原M消费证据与失败历史。',
300
- en: 'Add same-task exact scope amendment with original owner review of file hashes and write/read-only roles, original S observations and native contract reassessment; bind plans, writes and settlement to immutable scope revisions and retain actual M consumption and failure history during post-write refresh.',
301
- }
302
298
  const suppliedZh = process.env.ENTROROVE_RELEASE_NOTE_ZH?.trim()
303
299
  const suppliedEn = process.env.ENTROROVE_RELEASE_NOTE_EN?.trim()
304
300
  if (Boolean(suppliedZh) !== Boolean(suppliedEn)) {
@@ -307,6 +303,10 @@ function releaseNote(changed) {
307
303
  if (suppliedZh && suppliedEn) return {
308
304
  zh: suppliedZh.replaceAll(/\s+/g, ' '), en: suppliedEn.replaceAll(/\s+/g, ' '),
309
305
  }
306
+ if (changed.some(file => file.startsWith('scope-amendment-'))) return {
307
+ zh: '新增同一任务的精确范围补正:原账号审核文件哈希与写入/只读角色,原S签名真实事实并重评原合同;计划、写入和结算绑定不可变范围修订,改后刷新保留原M消费证据与失败历史。',
308
+ en: 'Add same-task exact scope amendment with original owner review of file hashes and write/read-only roles, original S observations and native contract reassessment; bind plans, writes and settlement to immutable scope revisions and retain actual M consumption and failure history during post-write refresh.',
309
+ }
310
310
  if (changed.includes('scope-runner-client.mjs')) return {
311
311
  zh: '补齐账号与任务隔离的本地签名器和真实快照接入,解析实际别名及类型声明;动态依赖仅进入受限规划,保留独立写入核验。',
312
312
  en: 'Connected account-bound scope signers and real snapshots, resolved actual aliases and declarations, and retained restricted planning for unresolved dynamic imports with separate mutation verification.',
package/releases.json CHANGED
@@ -1,4 +1,10 @@
1
1
  [
2
+ {
3
+ "version": "0.1.62",
4
+ "date": "2026-10-18",
5
+ "zh": "补齐本地新项目的受控创建与原生产步骤内迭代:原账号审批精确不存在路径和生产节点,S 与独立 M 签名校验真实基线,保留源文件只读保护、合同预算及失败历史。支持 PHP、JSON、原生模板、WXML、WXSS,通过实际创建、结算、测试和最终本地验收;钩子仍可关闭。",
6
+ "en": "Support governed creation and iteration of new local project files within their original producer and accepted plan. Bind exact absent paths and producers to owner approval, actual S and separate M evidence, protected sources, contract budgets and immutable failures. Cover PHP, JSON, native templates, WXML and WXSS through real writes, settlement, tests and final local acceptance while keeping hooks optional."
7
+ },
2
8
  {
3
9
  "version": "0.1.61",
4
10
  "date": "2026-10-18",
@@ -6,7 +6,7 @@ import path from 'node:path';
6
6
  import { sha256 } from './local-integrity.mjs';
7
7
 
8
8
  export async function scopeAmendmentMutation(location, state, challenge, facts) {
9
- const changed = challenge.files.filter(file => file.access === 'write'
9
+ const changed = challenge.files.filter(file => file.access !== 'read-only'
10
10
  && facts.files.find(actual => actual.path === file.path)?.sha256 !== challenge.currentFiles.find(current => current.path === file.path)?.sha256);
11
11
  if (!changed.length || challenge.purpose !== 'scope-revision-refresh') return undefined;
12
12
  const gatePassPath = location.identity.gatePassPath;
@@ -12,7 +12,9 @@ import { scopeAmendmentMutation } from './scope-amendment-mutation.mjs';
12
12
  async function inspectFiles(location, challenge) {
13
13
  const physical = new Set();
14
14
  for (const file of challenge.files) {
15
- const target = await scopeTarget(location.root, file.path);
15
+ const target = await scopeTarget(location.root, file.path, file.access === 'create');
16
+ if (!target.exists && file.access === 'create') continue;
17
+ if (file.access === 'create' && challenge.purpose === 'scope-revision') amendmentFail('A create role requires an actually absent target before approval is applied');
16
18
  if (!target.stat.isFile()) amendmentFail('Scope amendment permits only exact existing ordinary files');
17
19
  const identity = `${target.stat.dev}:${target.stat.ino}`;
18
20
  if (physical.has(identity)) amendmentFail('Scope amendment roles cannot alias the same physical file');
@@ -43,7 +45,8 @@ export async function observeScopeAmendment(location, state) {
43
45
  facts.snapshotEvidence = await verifyFreshScopeSnapshot(input, location.root, facts);
44
46
  for (const file of challenge.files) {
45
47
  const actual = facts.files.find(item => item.path === file.path);
46
- if (!actual?.exists || (challenge.purpose === 'scope-revision' || file.access === 'read-only') && actual.sha256 !== file.sha256) {
48
+ if (!actual || file.access !== 'create' && !actual.exists
49
+ || (challenge.purpose === 'scope-revision' || file.access === 'read-only') && actual.sha256 !== file.sha256) {
47
50
  amendmentFail('Scope amendment bytes differ from the exact original approved roles');
48
51
  }
49
52
  }
@@ -22,8 +22,9 @@ export function amendmentFiles(files, original) {
22
22
  if (!Array.isArray(files) || !files.length || files.length > 512) amendmentFail('Scope amendment requires a bounded complete exact role list');
23
23
  const requirements = new Set(original?.requirements?.length ? original.requirements.map(item => item.id) : ['task-goal']);
24
24
  for (const file of files) {
25
- amendmentExact(file, ['path', 'sha256', 'access', 'requirementRefs', 'reason']); scopePath(file.path);
26
- if (!hash.test(file.sha256) || !['write', 'read-only'].includes(file.access)
25
+ amendmentExact(file, ['path', 'sha256', 'access', 'requirementRefs', 'reason', ...(file.access === 'create' ? ['producerNodeRef'] : [])]); scopePath(file.path);
26
+ if (!hash.test(file.sha256) || !['write', 'read-only', 'create'].includes(file.access)
27
+ || file.access === 'create' && (!identifier.test(file.producerNodeRef) || file.sha256 !== sha256('entrorove.missing-file/1.0'))
27
28
  || typeof file.reason !== 'string' || !file.reason.trim() || file.reason.length > 2000
28
29
  || !Array.isArray(file.requirementRefs) || !file.requirementRefs.length || file.requirementRefs.length > 512
29
30
  || new Set(file.requirementRefs).size !== file.requirementRefs.length