@entrorove/skill 0.1.49 → 0.1.50

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.50 — 2026-10-16
4
+
5
+ - 修复 tsconfig 的 npm 配置继承,支持包与子路径、exports/typesVersions 及数组继承;按真实 pnpm 来源解析并记录配置哈希。依赖保持只读,越界及无法确定规范来源的引用报告具体路径和原因,保留原任务重试。
6
+ - Fixed tsconfig inheritance from npm packages, including package subpaths, exports/typesVersions and ordered parent arrays. Resolve pnpm configurations from their actual locations and retain metadata hashes. Dependencies remain read-only; escaping or unrepresentable canonical references report their paths and reasons while preserving the original task for retry.
7
+
3
8
  ## 0.1.49 — 2026-10-16
4
9
 
5
10
  - 修复本地签名快照扫描大量源码时的内存耗尽:优先分析当前授权目标,为源码与语法树设置内存边界,并及时释放 Vue 解析缓存。未完整分析的引用明确保持未知,全仓文件哈希与变更核验继续保留;超限目标返回具体路径和限制,原 flow、范围与队列可保留后重试。
package/IDE-EXECUTION.md CHANGED
@@ -64,7 +64,7 @@ The v2 progress sequence is durable and ordered: the first runtime step reports
64
64
 
65
65
  When intake returns `workflow-gate`, connect the current repository before invoking that gate: run `npx @entrorove/skill scope-connect <absolute repositoryRoot>` with JSON `{"flowId":"<original flowId>","paths":["<existing source file>"]}` on stdin. Use the concrete existing source files in the task's scope; new files belong in the later plan's declared artifacts. The adapter enrolls an OS-private Ed25519 scope signer for this accepted account and task, answers a server challenge, copies and verifies real source files, and submits the signed facts. It sends hashes and scope metadata rather than source contents or the private key. Enrollment grants scope inspection only; execution evidence and write passes retain their separate authority checks. An operator-configured signer cannot be replaced. After a successful connection, use the returned `nextInput` for `continue`, or explicitly send `payload: {"targetFiles":["<same existing source file>"]}` to the original `workflow-gate`. The connector uses `paths`; the gate uses `targetFiles`. Refresh an expired snapshot by reconnecting the same flow and path set. Show an explicit blocked result; query the original request ID after an unknown transport outcome before considering another attempt.
66
66
 
67
- Scope inspection resolves aliases from actual `tsconfig.json` or `jsconfig.json`, including relative `extends`. For plugin source compiled by a host project whose config is outside the source's ancestors, include `importContexts: [{"sourcePrefix":"<plugin source directory>","configPath":"<actual host tsconfig.json>"}]` in `scope-connect` input. Inspect the real build configuration first; never invent an alias or mark an unresolved import as external. These context paths remain inside the repository, their hashes enter the signed facts, and the local task binding freezes them.
67
+ Scope inspection resolves aliases from actual `tsconfig.json` or `jsconfig.json`, including relative and npm `extends` and ordered inheritance arrays. Npm configuration lookup uses the pinned TypeScript JSON-config resolver over controlled metadata reads, including scoped packages, subpaths, package `tsconfig`, `exports` and `typesVersions`. Configurations and package metadata enter the signed hashes; dependencies are read only, never executed. Repository-local pnpm links use their actual configuration location. Read-only external dependency packages support parents and mappings inside their reference boundary; references requiring an unrepresentable external canonical ancestor fail explicitly rather than selecting a different same-name repository package. For plugin source compiled by a host project whose config is outside the source's ancestors, include `importContexts: [{"sourcePrefix":"<plugin source directory>","configPath":"<actual host tsconfig.json>"}]` in `scope-connect` input. Inspect the real build configuration first; never invent an alias or mark an unresolved import as external. These context paths remain inside the repository, their hashes enter the signed facts, and the local task binding freezes them.
68
68
 
69
69
  Keep snapshot before-images distinct from a frozen execution plan's expected final file hashes. Controlled writes consume the original approved authority; the runner then verifies the actual planned final bytes. Never edit a signed plan or silently substitute a newer snapshot after an unknown or failed gate. Existing changes outside that authority require explicit revalidation of the same original flow.
70
70
 
package/SKILL.md CHANGED
@@ -5,7 +5,7 @@ description: Execute an engineering task through Entrorove, preserving its origi
5
5
 
6
6
  # entrorove · 熵巡
7
7
 
8
- Version: 0.1.49.
8
+ Version: 0.1.50.
9
9
 
10
10
  Entrorove applies to the whole task once selected. 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
 
@@ -0,0 +1,71 @@
1
+ import path from 'node:path';
2
+ import ts from 'typescript';
3
+
4
+ const virtualRoot = '/entrorove-repository/';
5
+ export function assertScopeConfigReference(from, resolved, boundary, field) {
6
+ if (boundary && resolved !== boundary.path && !resolved.startsWith(`${boundary.path}/`)) {
7
+ throw new Error(`Scope tsconfig ${field} from "${from}" (canonical "${boundary.resolved}") resolves to "${resolved}" outside read-only dependency reference "${boundary.path}"; its external canonical base cannot be represented inside the authorized repository`);
8
+ }
9
+ return resolved;
10
+ }
11
+ function repositoryPath(filename, within) {
12
+ const normalized = path.posix.normalize(filename);
13
+ if (!normalized.startsWith(virtualRoot)) return null;
14
+ return within('', normalized.slice(virtualRoot.length), false, 'extends resolution');
15
+ }
16
+ function validatePackageConfig(relative, source, within, referenceRoot) {
17
+ if (!relative.endsWith('/package.json')) return;
18
+ let manifest;
19
+ try { manifest = JSON.parse(source); }
20
+ catch { throw new Error(`Scope npm extends package metadata is invalid JSON: ${relative}`); }
21
+ if (typeof manifest?.tsconfig === 'string') {
22
+ const resolved = within(path.posix.dirname(relative), manifest.tsconfig, false, `package tsconfig in ${relative}`);
23
+ assertScopeConfigReference(relative, resolved, referenceRoot(relative), `package tsconfig ${JSON.stringify(manifest.tsconfig)}`);
24
+ }
25
+ }
26
+
27
+ /** Replay the pinned TypeScript resolver over asynchronously authorized metadata only. */
28
+ export async function scopeNpmConfig(metadata, fromConfig, specifier, within, canonicalPath, referenceRoot) {
29
+ if (specifier.split('/').some(part => !part || part === '.' || part === '..')) {
30
+ throw new Error(`Scope tsconfig extends has an invalid npm specifier: ${JSON.stringify(specifier)} in ${fromConfig}`);
31
+ }
32
+ if (referenceRoot(fromConfig)) {
33
+ const boundary = referenceRoot(fromConfig);
34
+ throw new Error(`Scope tsconfig npm extends ${JSON.stringify(specifier)} from "${fromConfig}" resolves through external canonical configuration "${boundary.resolved}"; ancestor package lookup outside dependency reference "${boundary.path}" cannot be represented inside the authorized repository`);
35
+ }
36
+ const sources = new Map(), pending = Symbol('authorized-config-read');
37
+ const lookup = filename => {
38
+ const relative = repositoryPath(filename, within);
39
+ if (relative === null) return null;
40
+ if (!sources.has(relative)) throw { pending, relative };
41
+ return sources.get(relative);
42
+ };
43
+ const host = {
44
+ fileExists: filename => lookup(filename) !== null,
45
+ readFile: filename => lookup(filename) ?? undefined,
46
+ getCurrentDirectory: () => virtualRoot.slice(0, -1),
47
+ getGlobalTypingsCacheLocation: () => virtualRoot.slice(0, -1),
48
+ useCaseSensitiveFileNames: true,
49
+ realpath: filename => {
50
+ const relative = repositoryPath(filename, within);
51
+ return relative === null ? filename : virtualRoot + within('', canonicalPath(relative), false, 'dependency realpath');
52
+ },
53
+ };
54
+ for (let probes = 0; probes < 1024; probes++) {
55
+ try {
56
+ const result = ts.nodeNextJsonConfigResolver(specifier, virtualRoot + fromConfig, host);
57
+ if (!result.resolvedModule) {
58
+ throw new Error(`Scope tsconfig npm extends ${JSON.stringify(specifier)} in ${fromConfig} references a missing or unexported actual configuration within the authorized repository`);
59
+ }
60
+ const relative = repositoryPath(result.resolvedModule.resolvedFileName, within);
61
+ if (relative === null) throw new Error(`Scope tsconfig npm extends ${JSON.stringify(specifier)} resolved outside the authorized repository`);
62
+ return relative;
63
+ } catch (error) {
64
+ if (error?.pending !== pending) throw error;
65
+ const source = await metadata(error.relative);
66
+ if (source !== null) validatePackageConfig(error.relative, source, within, referenceRoot);
67
+ sources.set(error.relative, source);
68
+ }
69
+ }
70
+ throw new Error(`Scope tsconfig npm extends ${JSON.stringify(specifier)} in ${fromConfig} exceeds the 1024-metadata-probe bound`);
71
+ }
@@ -1,6 +1,7 @@
1
1
  import { createHash } from 'node:crypto';
2
2
  import path from 'node:path';
3
3
  import ts from 'typescript';
4
+ import { scopeNpmConfig, assertScopeConfigReference } from './local-scope-config-extends.mjs';
4
5
  const missing = (error) => ['ENOENT', 'ENOTDIR'].includes(error?.code ?? '');
5
6
  function literal(value, field) {
6
7
  if (typeof value !== 'string' || !value || value !== value.trim() || value !== value.normalize('NFC')
@@ -81,6 +82,11 @@ function pathMatch(paths, specifier) {
81
82
  }
82
83
  return selected;
83
84
  }
85
+ function configCandidate(resolution, target) {
86
+ const base = resolution.baseUrl ?? resolution.pathsOrigin;
87
+ const boundary = resolution.baseUrl === undefined ? resolution.pathsReferenceRoot : resolution.baseUrlReferenceRoot;
88
+ return assertScopeConfigReference(base || '.', within(base, target), boundary, `mapping ${JSON.stringify(target)}`);
89
+ }
84
90
  function importCandidates(resolution, specifier) {
85
91
  if (typeof specifier !== 'string' || !specifier)
86
92
  throw new Error('Scope tsconfig import specifier must be nonempty');
@@ -92,18 +98,14 @@ function importCandidates(resolution, specifier) {
92
98
  }
93
99
  const match = pathMatch(resolution?.paths, specifier);
94
100
  if (match) {
95
- const base = resolution.baseUrl ?? resolution.pathsOrigin;
96
- return [...new Set(match.targets.map(target => within(base, target.replace('*', match.wildcard))))];
101
+ return [...new Set(match.targets.map(target => configCandidate(resolution, target.replace('*', match.wildcard))))];
97
102
  }
98
103
  if (specifier.startsWith('@/') || specifier.startsWith('#') || specifier.startsWith('~/')) {
99
104
  throw new Error('Scope local import alias requires an actual tsconfig or package-import mapping');
100
105
  }
101
- return resolution?.baseUrl !== undefined ? [within(resolution.baseUrl, specifier)] : [];
106
+ return resolution?.baseUrl !== undefined ? [configCandidate(resolution, specifier)] : [];
102
107
  }
103
- export async function scopeTsconfigImports(read, fromFile, configPath) {
104
- const canonical = within('', fromFile);
105
- if (canonical !== fromFile)
106
- throw new Error('Scope tsconfig source path must be canonical within the repository');
108
+ function configObservations(read) {
107
109
  const observed = new Map();
108
110
  const absent = new Set();
109
111
  let bytes = 0;
@@ -135,34 +137,50 @@ export async function scopeTsconfigImports(read, fromFile, configPath) {
135
137
  observed.set(relative, item);
136
138
  return data.toString('utf8');
137
139
  };
140
+ return { metadata, canonicalPath: relative => observed.get(relative)?.realPath ?? relative,
141
+ referenceRoot: relative => observed.get(relative)?.referenceRoot,
142
+ observations: () => [...observed.keys()].sort().map(relative => ({ path: relative, sha256: observed.get(relative).sha256 })) };
143
+ }
144
+ export async function scopeTsconfigImports(read, fromFile, configPath) {
145
+ const canonical = within('', fromFile);
146
+ if (canonical !== fromFile)
147
+ throw new Error('Scope tsconfig source path must be canonical within the repository');
148
+ const { metadata, canonicalPath, referenceRoot, observations } = configObservations(read);
149
+ let configurations = 0;
138
150
  const load = async (relative, ancestors, depth = 0) => {
139
- if (depth >= 10)
140
- throw new Error('Scope tsconfig extends exceeds the 10-configuration depth bound');
151
+ if (depth >= 10 || ++configurations > 512)
152
+ throw new Error('Scope tsconfig extends exceeds its 10-configuration depth or 512-configuration inspection bound');
141
153
  let source = await metadata(relative);
142
154
  if (source === null && !relative.endsWith('.json')) {
143
155
  relative += '.json';
144
156
  source = await metadata(relative);
145
157
  }
146
158
  if (source === null)
147
- throw new Error('Scope tsconfig extends references a missing actual configuration');
159
+ throw new Error(`Scope tsconfig extends references a missing actual configuration: ${relative}`);
148
160
  if (ancestors.has(relative))
149
161
  throw new Error('Scope tsconfig extends contains a configuration cycle');
150
162
  const config = parsedConfig(relative, source);
151
163
  const directory = path.posix.dirname(relative) === '.' ? '' : path.posix.dirname(relative);
152
- let inherited = { pathsOrigin: directory };
164
+ let inherited = {};
153
165
  if (config.extends !== undefined) {
154
- const extended = literal(config.extends, 'extends');
155
- if (!extended.startsWith('./') && !extended.startsWith('../'))
156
- throw new Error('Scope tsconfig npm extends is unsupported; use an actual repository-relative extends');
157
- inherited = await load(within(directory, extended, false, 'extends'), new Set([...ancestors, relative]), depth + 1);
166
+ const parents = Array.isArray(config.extends) ? config.extends : [config.extends];
167
+ if (parents.length > 128) throw new Error(`Scope tsconfig extends in ${relative} exceeds the 128-parent bound`);
168
+ for (const parent of parents) {
169
+ const extended = literal(parent, 'extends');
170
+ const target = extended.startsWith('./') || extended.startsWith('../')
171
+ ? assertScopeConfigReference(relative, within(directory, extended, false, 'extends'), referenceRoot(relative), `extends ${JSON.stringify(extended)}`)
172
+ : await scopeNpmConfig(metadata, relative, extended, within, canonicalPath, referenceRoot);
173
+ inherited = { ...inherited, ...await load(target, new Set([...ancestors, relative]), depth + 1) };
174
+ }
158
175
  }
159
176
  const options = config.compilerOptions === undefined ? {} : config.compilerOptions;
160
177
  if (!options || typeof options !== 'object' || Array.isArray(options))
161
178
  throw new Error('Scope tsconfig compilerOptions must be an object');
162
179
  const own = options;
163
180
  return { ...inherited,
164
- ...(own.baseUrl === undefined ? {} : { baseUrl: within(directory, own.baseUrl, true, 'baseUrl') }),
165
- ...(own.paths === undefined ? {} : { paths: pathsOption(own.paths), pathsOrigin: directory }) };
181
+ ...(own.baseUrl === undefined ? {} : { baseUrl: assertScopeConfigReference(relative, within(directory, own.baseUrl, true, 'baseUrl'), referenceRoot(relative), `baseUrl ${JSON.stringify(own.baseUrl)}`),
182
+ baseUrlReferenceRoot: referenceRoot(relative) }),
183
+ ...(own.paths === undefined ? {} : { paths: pathsOption(own.paths), pathsOrigin: directory, pathsReferenceRoot: referenceRoot(relative) }) };
166
184
  };
167
185
  let directory = path.posix.dirname(canonical);
168
186
  let resolution = null;
@@ -186,12 +204,11 @@ export async function scopeTsconfigImports(read, fromFile, configPath) {
186
204
  if (resolution?.paths)
187
205
  for (const targets of Object.values(resolution.paths))
188
206
  for (const target of targets) {
189
- within(resolution.baseUrl ?? resolution.pathsOrigin, target.replace('*', '__scope_wildcard__'), false, 'mapping');
207
+ configCandidate(resolution, target.replace('*', '__scope_wildcard__'));
190
208
  }
191
209
  return { candidates: specifier => importCandidates(resolution, specifier), mapped: specifier => {
192
210
  if (typeof specifier !== 'string' || !specifier)
193
211
  throw new Error('Scope tsconfig mapping lookup requires a nonempty specifier');
194
212
  return pathMatch(resolution?.paths, specifier) !== null;
195
- }, observations: [...observed.keys()].sort()
196
- .map(relative => ({ path: relative, sha256: observed.get(relative).sha256 })) };
213
+ }, observations: observations() };
197
214
  }
@@ -216,6 +216,27 @@ async function resolveImport(root, from, specifier, workspace, input, aliases, c
216
216
  return resolveLocalImport(root, relative);
217
217
  }
218
218
  const dependencyReference = relative => relative.split('/').includes('node_modules');
219
+ async function externalConfigReference(root, relative, resolved) {
220
+ const parts = relative.split('/'); let previous = root, boundary;
221
+ for (let index = 1; index <= parts.length; index++) {
222
+ const prefix = parts.slice(0, index).join('/'), current = await fs.realpath(path.join(root, prefix));
223
+ if (current !== root && !current.startsWith(`${root}${path.sep}`) && current !== path.join(previous, parts[index - 1])) {
224
+ boundary = { path: prefix, resolved };
225
+ }
226
+ previous = current;
227
+ }
228
+ return boundary;
229
+ }
230
+ async function configMetadata(root, relative, input) {
231
+ const target = await scopeTarget(root, relative, true, dependencyReference(relative));
232
+ if (!target.exists || !target.stat.isFile()) throw Object.assign(new Error(`Missing configuration file: ${relative}`), { code: 'ENOENT' });
233
+ const read = await scopeRead(root, relative, input), resolved = await fs.realpath(target.target);
234
+ const physical = path.relative(root, resolved).split(path.sep).join('/');
235
+ const outside = physical === '..' || physical.startsWith('../') || path.isAbsolute(physical);
236
+ const realPath = outside ? relative : physical;
237
+ const referenceRoot = outside ? await externalConfigReference(root, relative, resolved) : undefined;
238
+ return { path: relative, sha256: read.sha256, contentBase64: read.content.toString('base64'), realPath, referenceRoot };
239
+ }
219
240
  async function resolveLocalImport(root, relative, required = true) {
220
241
  if (relative.startsWith('../') || relative === '..') scopeFail('ENTROROVE_PATH_UNSAFE', 'local import escapes the repository');
221
242
  const replacements = /\.js$/.test(relative) ? [relative.replace(/\.js$/, '.ts'), relative.replace(/\.js$/, '.tsx')] : [];
@@ -248,10 +269,7 @@ export async function importGraph(root, originals, input = { repositoryRoot: roo
248
269
  const contexts = (input.importContexts ?? []).filter(context => relative === context.sourcePrefix || relative.startsWith(`${context.sourcePrefix}/`))
249
270
  .sort((a, b) => b.sourcePrefix.length - a.sourcePrefix.length);
250
271
  const configPath = contexts[0]?.configPath;
251
- const aliases = await scopeTsconfigImports(async target => {
252
- const item = await scopeRead(root, target, input);
253
- return { path: target, sha256: item.sha256, contentBase64: item.content.toString('base64') };
254
- }, relative, configPath);
272
+ const aliases = await scopeTsconfigImports(target => configMetadata(root, target, input), relative, configPath);
255
273
  for (const observed of aliases.observations) metadata.set(observed.path, observed);
256
274
  const declarations = declarationModules(read.content, relative);
257
275
  const imports = importSpecifiers(read.content, relative); dynamic ||= imports.dynamic;
@@ -275,10 +293,7 @@ export async function scopeCandidateImports(root, file, input = { repositoryRoot
275
293
  const workspace = await workspaceIndex(root, input);
276
294
  const context = (input.importContexts ?? []).filter(item => file.path === item.sourcePrefix || file.path.startsWith(`${item.sourcePrefix}/`))
277
295
  .sort((a, b) => b.sourcePrefix.length - a.sourcePrefix.length)[0];
278
- const aliases = await scopeTsconfigImports(async relative => {
279
- const read = await scopeRead(root, relative, input);
280
- return { path: relative, sha256: read.sha256, contentBase64: read.content.toString('base64') };
281
- }, file.path, context?.configPath);
296
+ const aliases = await scopeTsconfigImports(relative => configMetadata(root, relative, input), file.path, context?.configPath);
282
297
  const declarations = declarationModules(Buffer.from(file.content), file.path), edges = [];
283
298
  for (const specifier of parsed.specifiers) {
284
299
  const target = await resolveImport(root, file.path, specifier, workspace, input, aliases, context?.configPath, declarations);
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.49",
4
+ "version": "0.1.50",
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.49",
3
+ "version": "0.1.50",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "entrorove": "cli.mjs"
@@ -135,6 +135,7 @@
135
135
  "local-scope-repository.mjs",
136
136
  "local-scope-signature.mjs",
137
137
  "local-scope-config-imports.mjs",
138
+ "local-scope-config-extends.mjs",
138
139
  "local-scope-snapshot.mjs",
139
140
  "local-scope-state.mjs",
140
141
  "local-scope-workspaces.mjs",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": "entrorove.release-state/1.0",
3
- "version": "0.1.49",
4
- "digest": "d30e520019bb53e3293bce84f1a960ccfa65462274c961dcc659194f2ddb3c45",
3
+ "version": "0.1.50",
4
+ "digest": "c749866399a99cf122f71c00dca31cf49706a76f0998b7f3197d0763968468b5",
5
5
  "files": {
6
6
  "ide-code-mode.mjs": "f3f53357ba09727b3b597851976a24de93287c0faca5052448277d0904bb61f7",
7
7
  "ide-command.mjs": "dcd4b48305cc4f106e5e4509e794e4b46ef02de29afa9cccbbc2774308c81ff3",
@@ -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": "6c8b9abe17cc8f01aa3da2ab19ed34b2b9be3e3b38c1739fa6a7d763622c4864",
32
+ "IDE-EXECUTION.md": "4e76abb3b2e357de07665d7422204ce710af3cafc0ef946816de73bf1a8998e6",
33
33
  "REUSE-DISCIPLINE.md": "5b214cf313e7f715f52d54e28093a2d038f0f196ca64b15d1c49587b9d8eecf8",
34
34
  "reuse-discipline-release.mjs": "20ded9c21bd71b8779c454f5eba4c7c0a943ef99d94117b9bbef891d2ab6e3de",
35
35
  "local-final-gate16.mjs": "083aec470670e6cdb7ad2ab27b7a51b53a9ec3a8b4121cb9cbfa17d9940892c2",
@@ -81,9 +81,9 @@
81
81
  "CAPABILITY-MAP.md": "a0f0468a098725ced52a96dd8e22bfc7d1ce7681a8446ebf7dae3696c76c3385",
82
82
  "AGREEMENT.md": "f93a68e92c457200dd024610e65f74e478b8f60860f951da818b70561f1b9bf8",
83
83
  "DELIVERY-BOUNDARIES.md": "d1bb2895e23fc14bf1c76707bd1f6f03b39695501a78a0b7289dc37b099889dc",
84
- "package.json": "8be823b5756da9b393af966a4152bee301cb49f988823aaf757e8c51bf867085",
84
+ "package.json": "cdb1f686304d5d29d1feff1b1ec5b75e4e3dcff1f1da841dfb59d0502ab261e8",
85
85
  "manifest.json": "ab06e307795bc9da5add926752b6c4dbdaf18625090261a035aa356a679c504f",
86
- "release.mjs": "34a3da868e8b5b586b318f2e8275f2f238d48a20afceb7d51c0f783a120f6973",
86
+ "release.mjs": "e206cb6cabbb02542317bce283f7ba674621e67765a3eacef5741f2d6b1c58b2",
87
87
  "local-cli.mjs": "11461e4cf4f6a8612ff275bf8296ec57ff22281156cb2c72834d3c764ba422a1",
88
88
  "local-state-lock.mjs": "1dbf64264642a0851faf043e07ee9f66d2ad0508e9f799b0626246e42fae893e",
89
89
  "local-execution.mjs": "46fddd78cd954fb080c660affe90cdaa716695580427336acb820089441a8025",
@@ -122,7 +122,7 @@
122
122
  "local-scope-candidate.mjs": "8f0bd9606e70d4a0ebacdd3cd600ec3afed85e2bb3e1760aa1144cf55d4e028a",
123
123
  "local-scope-context.mjs": "79753abfc6c76089d17f003a1be537dfaea10d6731c542f7fc53f2a9996ed164",
124
124
  "local-scope-files.mjs": "96c301f2a45e5fa22f0b11fb15e5e564f118e53187fc7749263c78d5ed87b056",
125
- "local-scope-repository.mjs": "75ccc7a527b741350c9de5baff031a9606f1b423c951f41307170605d1366360",
125
+ "local-scope-repository.mjs": "56d7874326de2f90e47cf13d6b9839372044ea70ab15fbb7f7125bd13a87a087",
126
126
  "local-scope-git.mjs": "53bbbb6c4795db711b5bc164591a6ad79a561427da046d6bbe997dae6eb82829",
127
127
  "local-scope-git-reads.mjs": "5d8a2636bab955cb325cb693db7423e69512355887ae5b5af3b8cb615f5ddad0",
128
128
  "local-git-executable.mjs": "9391d716529025b1de3ee006df658a9d765b6ef29ad24ef9b7436829318e651e",
@@ -147,7 +147,8 @@
147
147
  "runtime/git-native-linux-v1.mjs": "cf5cb91426a105e62c0f07a8a230dec592dba46f85a3f708b4c4e8cfcd1126c6",
148
148
  "runtime/git-native-darwin-v1.mjs": "f88aab72dc86f94eb1115784872957cb8ed0f74205ae70e1ecd1939e7790e310",
149
149
  "local-scope-signature.mjs": "bd05e8cf9e23f9511a16844974362297b9e9d11930ff7b8ad2a490e8d7660fe9",
150
- "local-scope-config-imports.mjs": "53e510609066355318d886cd96f73a0fc8005a28857f6ab4eb6cb81c4857945b",
150
+ "local-scope-config-imports.mjs": "a399407227bbdd14468633bb6d25586df7c6a30a1ef0d1a80ab7c7b499d3fadf",
151
+ "local-scope-config-extends.mjs": "3ab4150b846b247e9e0851221123f220c5574699af651830e751f026ab33659e",
151
152
  "local-scope-snapshot.mjs": "c0f851470b98863a1d187825ed61ee6072d1c057b178fdc85ae29af02a3b250f",
152
153
  "local-scope-state.mjs": "8b600a91fc0068d7a8c0bb752ddba7ed30ada93daafb118d6cba2368fd94cb27",
153
154
  "local-scope-workspaces.mjs": "a44c34537e5ed2dcaf193a985e5bc05957989fbb160a650f9e37ba7d66eb2de8",
package/release.mjs CHANGED
@@ -90,6 +90,7 @@ const sourceFiles = [
90
90
  'runtime/git-native-darwin-v1.mjs',
91
91
  'local-scope-signature.mjs',
92
92
  'local-scope-config-imports.mjs',
93
+ 'local-scope-config-extends.mjs',
93
94
  'local-scope-snapshot.mjs',
94
95
  'local-scope-state.mjs',
95
96
  'local-scope-workspaces.mjs',
@@ -340,6 +341,7 @@ function releaseLabels() {
340
341
  'local-scope-files.mjs': { zh: '范围文件与安全读取', en: 'scope files and guarded reads' },
341
342
  'local-scope-repository.mjs': { zh: '真实仓库范围事实', en: 'actual repository scope facts' },
342
343
  'local-scope-config-imports.mjs': { zh: 'tsconfig 范围路径与依赖只读引用', en: 'tsconfig scope paths and read-only dependency references' },
344
+ 'local-scope-config-extends.mjs': { zh: 'tsconfig npm 配置继承解析', en: 'tsconfig npm configuration inheritance resolution' },
343
345
  'local-scope-git.mjs': { zh: '实际Git范围与变更事实', en: 'actual Git scope and change facts' },
344
346
  'local-scope-git-reads.mjs': { zh: '固定Git元数据与源码读取', en: 'fixed Git metadata and source reads' },
345
347
  'local-scope-git-comparison.mjs': { zh: 'Git范围比较接线', en: 'Git scope comparison wiring' },
package/releases.json CHANGED
@@ -1,4 +1,10 @@
1
1
  [
2
+ {
3
+ "version": "0.1.50",
4
+ "date": "2026-10-16",
5
+ "zh": "修复 tsconfig 的 npm 配置继承,支持包与子路径、exports/typesVersions 及数组继承;按真实 pnpm 来源解析并记录配置哈希。依赖保持只读,越界及无法确定规范来源的引用报告具体路径和原因,保留原任务重试。",
6
+ "en": "Fixed tsconfig inheritance from npm packages, including package subpaths, exports/typesVersions and ordered parent arrays. Resolve pnpm configurations from their actual locations and retain metadata hashes. Dependencies remain read-only; escaping or unrepresentable canonical references report their paths and reasons while preserving the original task for retry."
7
+ },
2
8
  {
3
9
  "version": "0.1.49",
4
10
  "date": "2026-10-16",