@entrorove/skill 0.1.48 → 0.1.49

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.49 — 2026-10-16
4
+
5
+ - 修复本地签名快照扫描大量源码时的内存耗尽:优先分析当前授权目标,为源码与语法树设置内存边界,并及时释放 Vue 解析缓存。未完整分析的引用明确保持未知,全仓文件哈希与变更核验继续保留;超限目标返回具体路径和限制,原 flow、范围与队列可保留后重试。
6
+ - Fixed memory exhaustion during local signed snapshots of large source repositories: inspect authorized targets first, bound source and syntax-tree retention, and release the Vue parser cache. Unresolved references remain explicitly unknown while whole-repository hashes and change verification are retained. Oversized targets report their exact path and limit so the original flow, scope, and queue can be preserved for retry.
7
+
3
8
  ## 0.1.48 — 2026-10-16
4
9
 
5
10
  - 新增标准命令 `install --host codex`,仅配置 Codex 并保留 Claude 的配置与技能副本;后续自动更新沿用已配置的宿主范围。安装命令守卫和旧版清理也按目标宿主限界。
@@ -2,6 +2,8 @@
2
2
 
3
3
  Apply these rules when adding to or changing an existing system. Reuse is assessed inside the current accepted repository; external projects, databases, accounts, sessions and keys are outside scope.
4
4
 
5
+ Snapshot scans stream whole-repository integrity hashes and bound semantic work to 1 MiB per source, 8 MiB of retained source, 512 files and 200,000 syntax nodes. Original target paths and proposed files receive capacity first. A resource-limited non-target source stays in the integrity comparison and is recorded as unresolved; `scanComplete` is false and absent references cannot prove a symbol unused. A target that exceeds a bound returns `ENTROROVE_DISCIPLINE_ANALYSIS_LIMIT` with its path and the exceeded limit. These are execution memory limits, never size-based review exemptions or approval thresholds. Preserve the original flow, signer, scope and queue during recovery. Upgrade with the standard managed installer, then retry the original `scope-connect` input; do not create a replacement task or bypass the host guard with an arbitrary Node environment wrapper.
6
+
5
7
  - D-1: Before another business mapping or fact definition, search actual definitions and reuse them. Snapshot planning records the whole repository comparison and AST usage review in `discipline-review.json`; its digest is covered by the signed original snapshot. Typed source-entity field mappings use the existing import/alias resolver to identify the same entity, then compare field/value sets. A conflicting second mapping is refused with the existing file and line. An unresolved semantic relation remains unknown. No overlap threshold is invented.
6
8
  - D-2: A rewrite must cite a concrete existing defect at file:line. “Clearer”, “more maintainable” and “more general” are not evidence. A necessary sensitive exception is submitted through `continue` → `workflow-discipline-review` on the original planning phase. Display the whole concrete proposal. Approval must be the original account's stored Confirm Protocol answer and audit, never a caller's `accepted:true`.
7
9
  - D-3: A parallel path requires frozen `policy.parallelPaths` and actual same-input, fieldwise equivalence evidence. Use the existing GoldenBaseline to pin baseline bytes and source hash. The approved runner reads the baseline and actual process output; the original output cannot be supplied anew by the implementation. Missing evidence yields incomplete, mismatch yields blocked with field names. Baselines come from the existing path's actual independent samples, not the new implementation's self-consistency tests.
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.48.
8
+ Version: 0.1.49.
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
 
@@ -2,6 +2,21 @@ import ts from 'typescript';
2
2
  import { archguardScriptSource } from './local-archguard-ast.mjs';
3
3
  import { canonical, sha256 } from './local-integrity.mjs';
4
4
 
5
+ export const disciplineAnalysisLimits = Object.freeze({ fileBytes: 1_048_576, sourceBytes: 8_388_608, files: 512, nodes: 200_000 });
6
+ function analysisLimit(file, reason, limit, required) {
7
+ if (required.has(file.path)) throw Object.assign(new Error(`Semantic inspection of "${file.path}" exceeds ${reason} (${limit}); preserve the original flow and split its approved source inspection before retrying`),
8
+ { code: 'ENTROROVE_DISCIPLINE_ANALYSIS_LIMIT' });
9
+ return { path: file.path, reason, limit };
10
+ }
11
+ function syntaxNodes(source, limit) {
12
+ const pending = [source]; let count = 0;
13
+ while (pending.length) {
14
+ if (++count > limit) return count;
15
+ ts.forEachChild(pending.pop(), child => { pending.push(child); });
16
+ }
17
+ return count;
18
+ }
19
+
5
20
  const location = (source, node) => ({ path: source.fileName, line: source.getLineAndCharacterOfPosition(node.getStart(source)).line + 1 });
6
21
  const unwrap = node => {
7
22
  while (node && (ts.isAsExpression(node) || ts.isSatisfiesExpression(node) || ts.isParenthesizedExpression(node))) node = node.expression;
@@ -58,7 +73,7 @@ function definition(source, node) {
58
73
  while (ancestor && !ts.isSourceFile(ancestor) && !publicDefinition(ancestor)) ancestor = ancestor.parent;
59
74
  const exported = Boolean(ancestor && !ts.isSourceFile(ancestor));
60
75
  const contract = exported && (ts.isInterfaceDeclaration(node) || ts.isTypeAliasDeclaration(node) || ts.isEnumDeclaration(node) || ts.isFunctionDeclaration(node));
61
- const signature = ts.isFunctionDeclaration(node) ? canonical({ parameters: node.parameters.map(item => item.getText(source)), type: node.type?.getText(source) ?? null }) : node.getText(source);
76
+ const signature = !contract ? null : ts.isFunctionDeclaration(node) ? canonical({ parameters: node.parameters.map(item => item.getText(source)), type: node.type?.getText(source) ?? null }) : node.getText(source);
62
77
  return { ...location(source, node), symbol, name, exported: Boolean(exported), contract: Boolean(contract),
63
78
  signatureDigest: contract ? sha256(signature) : null };
64
79
  }
@@ -110,11 +125,24 @@ function programFor(sources, edges) {
110
125
  });
111
126
  return ts.createProgram([...sources.keys()], { noLib: true, allowJs: true, checkJs: false }, host);
112
127
  }
113
- export function analyzeDisciplineSources(files, { edges = [], unresolved = [] } = {}) {
128
+ export function analyzeDisciplineSources(files, { edges = [], unresolved = [], requiredPaths = [] } = {}) {
114
129
  const sources = new Map(), unsupported = [];
130
+ const required = new Set(requiredPaths); let bytes = 0, nodes = 0;
115
131
  for (const file of files) {
132
+ const size = Buffer.byteLength(file.content);
133
+ const reason = size > disciplineAnalysisLimits.fileBytes ? 'source-file-byte-limit'
134
+ : bytes + size > disciplineAnalysisLimits.sourceBytes ? 'source-total-byte-limit'
135
+ : sources.size >= disciplineAnalysisLimits.files ? 'source-file-count-limit' : null;
136
+ if (reason) { unsupported.push(analysisLimit(file, reason, reason === 'source-file-byte-limit' ? disciplineAnalysisLimits.fileBytes
137
+ : reason === 'source-total-byte-limit' ? disciplineAnalysisLimits.sourceBytes : disciplineAnalysisLimits.files, required)); continue; }
138
+ bytes += size;
116
139
  const parsed = archguardScriptSource(file);
117
140
  if (!parsed || parsed.parseDiagnostics.length) { unsupported.push({ path: file.path, reason: parsed ? 'syntax-unresolved' : 'language-unresolved' }); continue; }
141
+ const count = syntaxNodes(parsed, disciplineAnalysisLimits.nodes - nodes);
142
+ if (nodes + count > disciplineAnalysisLimits.nodes) {
143
+ unsupported.push(analysisLimit(file, 'syntax-node-limit', disciplineAnalysisLimits.nodes, required)); continue;
144
+ }
145
+ nodes += count;
118
146
  sources.set(file.path, parsed);
119
147
  }
120
148
  const program = programFor(sources, edges), checker = program.getTypeChecker(), definitions = [], mappings = [], references = new Map();
@@ -5,7 +5,7 @@ import { canonical, sha256 } from './local-integrity.mjs';
5
5
  import { mutationRead14, mutationPath14, mutationTarget14, mutationFail14 } from './local-mutation-files.mjs';
6
6
  import { budgetBindingForRead } from './local-budget-reads.mjs';
7
7
  import { budgetStatus } from './local-budget.mjs';
8
- import { analyzeDisciplineSources } from './local-discipline-analysis.mjs';
8
+ import { analyzeDisciplineSources, disciplineAnalysisLimits } from './local-discipline-analysis.mjs';
9
9
  import { importGraph, scopeCandidateImports } from './local-scope-repository.mjs';
10
10
  import { nativeDisciplineDefinitions } from './local-discipline-native.mjs';
11
11
 
@@ -19,6 +19,14 @@ function withinBudgetScope(relative, scope) {
19
19
  && !scope.forbiddenPaths?.some(forbidden => within(relative, forbidden));
20
20
  }
21
21
  const sameFile = (left, right) => ['dev', 'ino', 'size', 'mtimeMs', 'ctimeMs', 'mode'].every(key => left[key] === right[key]);
22
+ function sourceLimit(relative, bytes, sources, used, required) {
23
+ const reason = bytes > disciplineAnalysisLimits.fileBytes ? 'source-file-byte-limit'
24
+ : used + bytes > disciplineAnalysisLimits.sourceBytes ? 'source-total-byte-limit'
25
+ : sources.length >= disciplineAnalysisLimits.files ? 'source-file-count-limit' : null;
26
+ if (reason && required.has(relative)) mutationFail14('ENTROROVE_DISCIPLINE_ANALYSIS_LIMIT',
27
+ `Semantic inspection of "${relative}" (${bytes} bytes) exceeds ${reason}; limits are ${disciplineAnalysisLimits.fileBytes} bytes per file, ${disciplineAnalysisLimits.sourceBytes} total bytes and ${disciplineAnalysisLimits.files} files. Preserve the original flow and split its approved inspection before retrying`);
28
+ return reason;
29
+ }
22
30
  async function integrityOnlyFile(root, relative) {
23
31
  // This path returns only an integrity digest. It never exposes source bytes or
24
32
  // contributes semantic facts outside the signed source-read scope.
@@ -47,12 +55,19 @@ async function inventory(root, prefix = '') {
47
55
  }
48
56
  export async function disciplineRepositoryObservation(input, root, { analyze = false, overrides = new Map() } = {}) {
49
57
  const paths = await inventory(root), files = [], sources = [], unresolved = [];
58
+ const required = new Set([...(input.paths ?? []), ...(input.targetPath ? [input.targetPath] : []), ...overrides.keys()]);
59
+ const ordered = [...paths].sort((a, b) => Number(required.has(b)) - Number(required.has(a)) || (a < b ? -1 : a > b ? 1 : 0));
60
+ let sourceBytes = 0;
50
61
  const binding = await budgetBindingForRead(input), budget = binding ? await budgetStatus(binding) : null;
51
62
  const restricted = budget?.enforced ? budget.scope : null;
52
63
  if (restricted && [...overrides.keys()].some(relative => !withinBudgetScope(relative, restricted))) {
53
64
  mutationFail14('ENTROROVE_BUDGET_SCOPE', 'candidate analysis is outside the original cloud task scope');
54
65
  }
55
- for (const relative of paths) {
66
+ for (const [relative, content] of overrides) if (analyze && !paths.includes(relative) && semanticSource(relative)) {
67
+ const bytes = Buffer.byteLength(content); sourceLimit(relative, bytes, sources, sourceBytes, required);
68
+ sources.push({ path: relative, content }); sourceBytes += bytes;
69
+ }
70
+ for (const relative of ordered) {
56
71
  const stat = await fs.lstat(path.join(root, relative));
57
72
  if (stat.isSymbolicLink()) {
58
73
  files.push({ path: relative, sha256: sha256(await fs.readlink(path.join(root, relative))), mode: stat.mode & 0o777, kind: 'symlink' });
@@ -60,24 +75,27 @@ export async function disciplineRepositoryObservation(input, root, { analyze = f
60
75
  }
61
76
  const semantic = analyze && semanticSource(relative);
62
77
  const allowed = !restricted || withinBudgetScope(relative, restricted);
63
- const read = semantic && allowed ? await mutationRead14(input, root, relative) : await integrityOnlyFile(root, relative);
78
+ const bytes = overrides.has(relative) ? Buffer.byteLength(overrides.get(relative)) : stat.size;
79
+ const limited = semantic && allowed ? sourceLimit(relative, bytes, sources, sourceBytes, required) : null;
80
+ const read = semantic && allowed && !limited ? await mutationRead14(input, root, relative) : await integrityOnlyFile(root, relative);
64
81
  files.push({ path: relative, sha256: read.sha256, mode: read.mode, kind: 'file' });
65
- if (semantic && allowed) sources.push({ path: relative, content: overrides.get(relative) ?? read.content.toString('utf8') });
82
+ if (semantic && allowed && !limited) { sources.push({ path: relative, content: overrides.get(relative) ?? read.content.toString('utf8') }); sourceBytes += bytes; }
83
+ else if (limited) unresolved.push({ path: relative, reason: limited, bytes });
66
84
  else if (semantic && !allowed) unresolved.push({ path: relative, reason: 'outside-signed-source-scope' });
67
85
  }
68
86
  if (canonical(paths) !== canonical(await inventory(root))) mutationFail14('ENTROROVE_DISCIPLINE_SCAN_CHANGED', 'Repository inventory changed while observing its original baseline');
87
+ files.sort((a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0);
69
88
  const comparison = { schemaVersion: 'entrorove.repository-comparison/1.0', files,
70
89
  scope: 'whole-repository-including-ignored-files', excludedDirectoryNames: [...excluded].sort() };
71
90
  if (!analyze) return { comparison };
72
91
  // The existing resolver supplies actual aliases, package exports and import edges.
73
92
  // Unsupported/dynamic references stay unknown; they are never converted to unused.
74
- const roots = sources.filter(file => /\.[cm]?[jt]sx?$/i.test(file.path)).map(file => ({ path: file.path, exists: true }));
75
- for (const [relative, content] of overrides) if (!paths.includes(relative) && semanticSource(relative)) sources.push({ path: relative, content });
93
+ const roots = sources.filter(file => paths.includes(file.path) && /\.[cm]?[jt]sx?$/i.test(file.path)).map(file => ({ path: file.path, exists: true }));
76
94
  let graph;
77
- try { graph = roots.length ? await importGraph(root, roots, input) : { edges: [], dynamicSources: [], complete: true }; }
95
+ try { graph = roots.length ? await importGraph(root, roots, input, disciplineAnalysisLimits) : { edges: [], dynamicSources: [], complete: true }; }
78
96
  catch (error) {
79
97
  if (!['ENTROROVE_IMPORT_UNRESOLVED', 'ENTROROVE_IMPORT_INVALID', 'ENTROROVE_IMPORT_UNSUPPORTED', 'ENTROROVE_SCOPE_LIMIT', 'ENTROROVE_BUDGET_SCOPE'].includes(error.code)) throw error;
80
- graph = { edges: [], dynamicSources: [], complete: false }; unresolved.push({ reason: error.code });
98
+ graph = { edges: [], dynamicSources: [], complete: false }; unresolved.push({ reason: error.code, message: error.message });
81
99
  }
82
100
  for (const [relative, content] of overrides) if (semanticSource(relative) && /\.[cm]?[jt]sx?$/i.test(relative)) {
83
101
  try {
@@ -89,7 +107,7 @@ export async function disciplineRepositoryObservation(input, root, { analyze = f
89
107
  unresolved.push({ path: relative, reason: error.code });
90
108
  }
91
109
  }
92
- const analysis = analyzeDisciplineSources(sources, { edges: graph.edges,
110
+ const analysis = analyzeDisciplineSources(sources, { edges: graph.edges, requiredPaths: [...required],
93
111
  unresolved: [...unresolved, ...graph.dynamicSources.map(item => ({ path: item.path, reason: 'dynamic-import' }))] });
94
112
  analysis.definitions.push(...await nativeDisciplineDefinitions(sources));
95
113
  return { comparison, analysis, scanComplete: graph.complete && analysis.unresolved.length === 0 };
@@ -4,7 +4,7 @@ import path from 'node:path';
4
4
  import { promisify } from 'node:util';
5
5
  import { builtinModules } from 'node:module';
6
6
  import ts from 'typescript';
7
- import { parse as parseVue } from '@vue/compiler-sfc';
7
+ import { parse as parseVue, parseCache as vueParseCache } from '@vue/compiler-sfc';
8
8
  import { lineCount, observedScopeRisk, packageBoundary, scopeFail, scopeFiles, scopeRead, scopeTarget, stableScope } from './local-scope-files.mjs';
9
9
  import { sha256 } from './local-integrity.mjs';
10
10
  import { workspaceImport, workspaceIndex } from './local-scope-workspaces.mjs';
@@ -142,6 +142,7 @@ function scriptImports(source, filename) {
142
142
  function vueScripts(source, filename) {
143
143
  const { descriptor, errors } = parseVue(source, { filename, sourceMap: false,
144
144
  templateParseOptions: { expressionPlugins: ['typescript'] } });
145
+ vueParseCache.clear();
145
146
  if (errors.length) scopeFail('ENTROROVE_IMPORT_INVALID', 'component has invalid or unterminated syntax');
146
147
  if (descriptor.customBlocks.length || descriptor.template?.lang || descriptor.template?.src) {
147
148
  scopeFail('ENTROROVE_IMPORT_UNSUPPORTED', 'component dependency inspection requires supported inline template syntax');
@@ -225,14 +226,22 @@ async function resolveLocalImport(root, relative, required = true) {
225
226
  if (required) scopeFail('ENTROROVE_IMPORT_UNRESOLVED', 'a local import has no resolvable source file');
226
227
  return null;
227
228
  }
228
- export async function importGraph(root, originals, input = { repositoryRoot: root }) {
229
+ export async function importGraph(root, originals, input = { repositoryRoot: root }, limits = {}) {
229
230
  const pending = originals.filter(file => file.exists !== false).map(file => file.path); const visited = new Map(); const edges = []; let dynamic = false;
231
+ let sourceBytes = 0;
230
232
  const dynamicSources = [];
231
233
  const workspace = await workspaceIndex(root, input);
232
234
  const metadata = new Map(workspace.metadata.map(item => [item.path, item]));
233
235
  while (pending.length) {
234
236
  const relative = pending.shift(); if (visited.has(relative)) continue;
235
237
  if (visited.size >= 1000) scopeFail('ENTROROVE_SCOPE_LIMIT', 'import graph exceeds the 1000-file inspection bound');
238
+ if (limits.fileBytes || limits.sourceBytes) {
239
+ const target = await scopeTarget(root, relative, false, dependencyReference(relative));
240
+ if (target.stat.size > (limits.fileBytes ?? Infinity) || sourceBytes + target.stat.size > (limits.sourceBytes ?? Infinity)) {
241
+ scopeFail('ENTROROVE_SCOPE_LIMIT', `Import inspection of "${relative}" (${target.stat.size} bytes) exceeds its bounded semantic scan (${limits.fileBytes} bytes per file, ${limits.sourceBytes} total bytes)`);
242
+ }
243
+ sourceBytes += target.stat.size;
244
+ }
236
245
  const read = await scopeRead(root, relative, input); const boundary = await packageBoundary(root, relative, input);
237
246
  visited.set(relative, { path: relative, sha256: read.sha256, module: boundary.path, boundary });
238
247
  if (!sourceExtension.test(relative)) continue;
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.48",
4
+ "version": "0.1.49",
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.48",
3
+ "version": "0.1.49",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "entrorove": "cli.mjs"
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "schemaVersion": "entrorove.release-state/1.0",
3
- "version": "0.1.48",
4
- "digest": "6f79c0e2c12d4e8766801bf117bcf73070156ba89fb87e4b1137c9706b8f7df3",
3
+ "version": "0.1.49",
4
+ "digest": "d30e520019bb53e3293bce84f1a960ccfa65462274c961dcc659194f2ddb3c45",
5
5
  "files": {
6
6
  "ide-code-mode.mjs": "f3f53357ba09727b3b597851976a24de93287c0faca5052448277d0904bb61f7",
7
7
  "ide-command.mjs": "dcd4b48305cc4f106e5e4509e794e4b46ef02de29afa9cccbbc2774308c81ff3",
@@ -12,14 +12,14 @@
12
12
  "ide-results.mjs": "dfe0d3f773c65a9fc21056538d7005012c982ed4509bc0410d7f62813d0863fd",
13
13
  "ide-queue.mjs": "806e716c775fd0079417027b135977c8516f47dddb0bc5ca19e32a355dab0e9e",
14
14
  "local-discipline-actions.mjs": "2379c08d0f49c44068f8239db7e514d75885f4606b1b88a7a36e4ff19167caca",
15
- "local-discipline-analysis.mjs": "ebea932438a53a157d5d07a5d68366496eee121a2c67cecfb4fdb2d5aa9763eb",
15
+ "local-discipline-analysis.mjs": "f49e67a2eb2f19f8eb7c4226d481842b38c0f19b495ad0149cbf649baae16bb9",
16
16
  "local-discipline-batch.mjs": "2cc90dbae55efdee0c445da399c0a9acafa92e915344c25208ebca554fc4c9e9",
17
17
  "local-discipline-contracts.mjs": "6cf8a3d132fdb9074eb1441600afe7aa199df33e88a71a660d9db534c14f19e4",
18
18
  "local-discipline-contracts.d.mts": "defc684c78dc88afa1c54340ab4a01ae36db7aa11257cbe1f5cd323f608c78c4",
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": "d818aa6137459ef200892479cc8c47fe82c884dc0e76dc7e6d45a6b41a13c6ec",
22
+ "local-discipline-repository.mjs": "ffd31e9b2946a9784d4ab59cee5345318d2152816ce995ed5dac11efa4096bc4",
23
23
  "local-discipline-snapshot.mjs": "8fd35b2cfbece8f64579f144f589a66dec9b6022d50fe931c4c1f886cb83134d",
24
24
  "local-runner-discipline.mjs": "86f451de2f1e12a24f5596a29828891c1eba13cd4714ed0c18a77d66cecef934",
25
25
  "local-integrity.d.mts": "21357f306234bd841c0d3d90bf2d09f7663f63746f897b9f38190428ae8198b3",
@@ -30,7 +30,7 @@
30
30
  "snapshot-retention.mjs": "4f8919fe8ec49fb4c23e080a8ad2fa3a9282bca3fffe7cf55c64e89ef316697e",
31
31
  "snapshot-cleanup-journal.mjs": "76a9684cc95b4eb076e1298d78a9dff37948b00d9607b8f546c599072d3ed331",
32
32
  "IDE-EXECUTION.md": "6c8b9abe17cc8f01aa3da2ab19ed34b2b9be3e3b38c1739fa6a7d763622c4864",
33
- "REUSE-DISCIPLINE.md": "295ecd41c931b00c21d009ab65ac160f0e2ab81b4000ed498d2e8e97c2dc6c63",
33
+ "REUSE-DISCIPLINE.md": "5b214cf313e7f715f52d54e28093a2d038f0f196ca64b15d1c49587b9d8eecf8",
34
34
  "reuse-discipline-release.mjs": "20ded9c21bd71b8779c454f5eba4c7c0a943ef99d94117b9bbef891d2ab6e3de",
35
35
  "local-final-gate16.mjs": "083aec470670e6cdb7ad2ab27b7a51b53a9ec3a8b4121cb9cbfa17d9940892c2",
36
36
  "local-final-gate16-checks.mjs": "1dd30e9666d458d8b12ca6e4975f6f0ac8450c3ea9cbecc7401ae037f66b589a",
@@ -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": "0c955612d2f737e8661af84c1efb6e9e7fe6bb9ec1dfadd7776c61be177261f2",
125
+ "local-scope-repository.mjs": "75ccc7a527b741350c9de5baff031a9606f1b423c951f41307170605d1366360",
126
126
  "local-scope-git.mjs": "53bbbb6c4795db711b5bc164591a6ad79a561427da046d6bbe997dae6eb82829",
127
127
  "local-scope-git-reads.mjs": "5d8a2636bab955cb325cb693db7423e69512355887ae5b5af3b8cb615f5ddad0",
128
128
  "local-git-executable.mjs": "9391d716529025b1de3ee006df658a9d765b6ef29ad24ef9b7436829318e651e",
package/releases.json CHANGED
@@ -1,4 +1,10 @@
1
1
  [
2
+ {
3
+ "version": "0.1.49",
4
+ "date": "2026-10-16",
5
+ "zh": "修复本地签名快照扫描大量源码时的内存耗尽:优先分析当前授权目标,为源码与语法树设置内存边界,并及时释放 Vue 解析缓存。未完整分析的引用明确保持未知,全仓文件哈希与变更核验继续保留;超限目标返回具体路径和限制,原 flow、范围与队列可保留后重试。",
6
+ "en": "Fixed memory exhaustion during local signed snapshots of large source repositories: inspect authorized targets first, bound source and syntax-tree retention, and release the Vue parser cache. Unresolved references remain explicitly unknown while whole-repository hashes and change verification are retained. Oversized targets report their exact path and limit so the original flow, scope, and queue can be preserved for retry."
7
+ },
2
8
  {
3
9
  "version": "0.1.48",
4
10
  "date": "2026-10-16",