dsh-vibe-math 2.7.0 → 2.7.1

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.
Files changed (41) hide show
  1. package/README.en.md +5 -0
  2. package/README.md +5 -0
  3. package/cordis.patch.yml +6 -0
  4. package/docs/math-computation.md +44 -2
  5. package/docs/release-notes/RELEASE-NOTES-2.7.1.en.md +86 -0
  6. package/docs/release-notes/RELEASE-NOTES-2.7.1.md +86 -0
  7. package/package.json +5 -3
  8. package/prompt-corpus-persona/persona-corpus.json +8 -8
  9. package/prompt-corpus-persona/persona-corpus.md +12 -0
  10. package/prompt-corpus-v2/formal-verify-v2.json +162 -96
  11. package/prompt-corpus-v2/formal-verify-v2.md +949 -0
  12. package/prompt-corpus-v3/formal-verify-v3.json +171 -57
  13. package/prompt-corpus-v3/formal-verify-v3.md +1146 -0
  14. package/prompt-corpus-v4/formal-verify-v4.json +10 -10
  15. package/prompt-corpus-v4/formal-verify-v4.md +20 -0
  16. package/prompt-corpus-v5/prompt-corpus-v5.json +61 -61
  17. package/prompt-corpus-v5/prompt-corpus-v5.md +61 -0
  18. package/tests/audit-math-computation-contract.mjs +13 -0
  19. package/tests/audit-math-computation-parity.mjs +30 -1
  20. package/tests/audit-math-computation-sensitivity.mjs +1 -1
  21. package/tests/e2e-v5-round2.test.mjs +7 -0
  22. package/tests/formal-verify-v2.test.mjs +70 -2
  23. package/tests/formal-verify-v3.test.mjs +84 -2
  24. package/tests/helpers/math-computation-fake-seam.mjs +30 -2
  25. package/tests/math-computation-shared.test.mjs +304 -2
  26. package/vibe-math-v2/agent.cordis.yml +2 -0
  27. package/vibe-math-v2/math-computation.js +390 -47
  28. package/vibe-math-v2/math-engines.js +47 -6
  29. package/vibe-math-v2/vibe-math-v2.js +17 -1
  30. package/vibe-math-v3/agent.cordis.yml +2 -0
  31. package/vibe-math-v3/math-computation.js +390 -47
  32. package/vibe-math-v3/math-engines.js +47 -6
  33. package/vibe-math-v3/vibe-math-v3.js +17 -1
  34. package/vibe-math-v4/agent.cordis.yml +4 -0
  35. package/vibe-math-v4/math-computation.js +390 -47
  36. package/vibe-math-v4/math-engines.js +47 -6
  37. package/vibe-math-v4/vibe-math-v4.js +15 -0
  38. package/vibe-math-v5/agent.cordis.yml +4 -0
  39. package/vibe-math-v5/math-computation.js +390 -47
  40. package/vibe-math-v5/math-engines.js +47 -6
  41. package/vibe-math-v5/vibe-math-v5.js +15 -3
@@ -22,14 +22,47 @@ export const MATH_ENGINES = {
22
22
  candidates: ['python3', 'python', 'py'], winPrefix: ['-3'],
23
23
  versionArgv: ['--version'], versionRe: '(\\d+\\.\\d+\\.\\d+)',
24
24
  scriptArgv: ['<script>'], evalArgv: ['-c', '<expr>'], stdinArgv: ['-'], ext: '.py',
25
- probeCode: "import importlib.util,sys;print('|'.join('%s:%s'%(p,'ok' if importlib.util.find_spec(p) else 'missing') for p in sys.argv[1:]))",
26
- packageProbe: { argv: ['-c', '<probeCode>', '<pkgs>'], parse: 'pairs' },
25
+ // round-7 (live): NO shell metacharacters (`|`, `%`) in any probe argv - a real host rejected
26
+ // them with a null spawn. One line per package: "name ok|missing".
27
+ probeCode: "import importlib.util,sys\nfor p in sys.argv[1:]: print(p, 'ok' if importlib.util.find_spec(p) is not None else 'missing')",
28
+ // round-7 (finding 6, found on the real bundled python): the probe code iterates `sys.argv[1:]`,
29
+ // so the names must be SEPARATE argv items - the old comma-joined `<pkgs>` made it look up one
30
+ // package literally named "numpy,pandas" and reported everything missing.
31
+ packageProbe: { argv: ['-c', '<probeCode>', '<pkgs...>'], parse: 'pairs' },
27
32
  license: 'free', argErrorHints: ARG_ERROR_HINTS,
28
33
  install: {
29
34
  manager: 'pip',
30
35
  userArgv: ['<exe>', '-m', 'pip', 'install', '--user', '<pkg>'],
31
36
  systemArgv: ['<exe>', '-m', 'pip', 'install', '<pkg>'],
32
37
  uninstallArgv: ['<exe>', '-m', 'pip', 'uninstall', '-y', '<pkg>'],
38
+ // Round-6 (B): DISPATCH by the detected interpreter environment. `pip` is the documented
39
+ // fallback; the module picks conda/mamba/uv only when the interpreter's OWN environment says so
40
+ // (detect, don't guess) and the plan states which manager it assumed.
41
+ managers: {
42
+ conda: {
43
+ detect: 'conda-markers',
44
+ userArgv: ['conda', 'install', '-y', '-c', 'conda-forge', '<pkg>'],
45
+ uninstallArgv: ['conda', 'remove', '-y', '<pkg>'],
46
+ systemUnsupportedReason: 'conda 环境是用户级的;系统级安装不在 conda 的概念里(本工具只出用户级计划)',
47
+ },
48
+ mamba: {
49
+ detect: 'conda-markers',
50
+ userArgv: ['mamba', 'install', '-y', '-c', 'conda-forge', '<pkg>'],
51
+ uninstallArgv: ['mamba', 'remove', '-y', '<pkg>'],
52
+ systemUnsupportedReason: 'mamba 环境是用户级的;系统级安装不在 mamba 的概念里(本工具只出用户级计划)',
53
+ },
54
+ uv: {
55
+ detect: 'uv-next-to-interpreter',
56
+ userArgv: ['uv', 'pip', 'install', '<pkg>'],
57
+ uninstallArgv: ['uv', 'pip', 'uninstall', '<pkg>'],
58
+ systemUnsupportedReason: 'uv 装进当前虚拟环境(用户级);系统级需要发行版包管理器,本工具只出用户级计划',
59
+ },
60
+ pip: {
61
+ detect: 'fallback',
62
+ systemArgv: ['<exe>', '-m', 'pip', 'install', '<pkg>'],
63
+ uninstallArgv: ['<exe>', '-m', 'pip', 'uninstall', '-y', '<pkg>'],
64
+ },
65
+ },
33
66
  },
34
67
  userInstall: { windows: 'winget install --id Python.Python.3.12', macos: 'brew install python', linux: 'apt install python3' },
35
68
  },
@@ -38,13 +71,16 @@ export const MATH_ENGINES = {
38
71
  candidates: ['Rscript', 'R'],
39
72
  versionArgv: ['--version'], versionRe: '(\\d+\\.\\d+\\.\\d+)',
40
73
  scriptArgv: ['<script>'], evalArgv: ['-e', '<expr>'], stdinArgv: ['--no-save', '--slave'], ext: '.R',
41
- probeCode: "cat(paste(sapply(strsplit('__PKGS__',',')[[1]],function(p) paste0(p,':',requireNamespace(p,quietly=TRUE))),collapse='|'))",
74
+ // round-7 (live): line-per-package, no `|` in the argv.
75
+ probeCode: "for (p in strsplit('__PKGS__',',')[[1]]) cat(p, if (requireNamespace(p, quietly=TRUE)) 'ok' else 'missing', '\\n')",
42
76
  packageProbe: { argv: ['-e', '<probeCode>'], parse: 'pairs' },
43
77
  license: 'free', argErrorHints: ARG_ERROR_HINTS,
44
78
  install: {
45
79
  manager: 'r',
46
80
  userArgv: ['<exe>', '-e', "install.packages('__PKG__',lib=Sys.getenv('R_LIBS_USER'),repos='https://cloud.r-project.org')"],
47
81
  uninstallArgv: ['<exe>', '-e', "remove.packages('__PKG__',lib=Sys.getenv('R_LIBS_USER'))"],
82
+ // Round-6 (C): user-only BY DESIGN, and the refusal now says why per engine.
83
+ systemUnsupportedReason: 'R 的用户库是 R_LIBS_USER;系统级安装要写发行版的包目录(需 root 或发行版包管理器),本工具只出用户级计划',
48
84
  },
49
85
  userInstall: { windows: 'winget install --id RProject.R', macos: 'brew install r', linux: 'apt install r-base' },
50
86
  },
@@ -54,13 +90,15 @@ export const MATH_ENGINES = {
54
90
  versionArgv: ['--version'], versionRe: '(\\d+\\.\\d+\\.\\d+)',
55
91
  scriptArgv: ['--no-gui', '--quiet', '<script>'], evalArgv: ['--no-gui', '--quiet', '--eval', '<expr>'],
56
92
  stdinArgv: ['--no-gui', '--quiet'], ext: '.m',
57
- probeCode: "s=pkg('list'); n={'__QPKGS__'}; for i=1:numel(n); printf('%s:%s|',n{i},merge(any(cellfun(@(x) strcmp(x.name,n{i}),s)),'ok','missing')); end",
93
+ // round-7 (live): line-per-package via disp, no `|` and no `%` in the argv.
94
+ probeCode: "s=pkg('list'); n={'__QPKGS__'}; for i=1:numel(n); if any(cellfun(@(x) strcmp(x.name,n{i}),s)); disp([n{i} ' ok']); else; disp([n{i} ' missing']); end; end",
58
95
  packageProbe: { argv: ['--no-gui', '--quiet', '--eval', '<probeCode>'], parse: 'pairs' },
59
96
  license: 'free', argErrorHints: ARG_ERROR_HINTS,
60
97
  install: {
61
98
  manager: 'octave-pkg',
62
99
  userArgv: ['<exe>', '--no-gui', '--quiet', '--eval', "pkg install -forge __PKG__"],
63
100
  uninstallArgv: ['<exe>', '--no-gui', '--quiet', '--eval', 'pkg uninstall __PKG__'],
101
+ systemUnsupportedReason: 'Octave 的 pkg install 装进用户包目录;系统级要写 Octave 的 share/packages(需 root),本工具只出用户级计划',
64
102
  },
65
103
  userInstall: { windows: 'winget install --id GNU.Octave', macos: 'brew install octave', linux: 'apt install octave' },
66
104
  },
@@ -76,6 +114,7 @@ export const MATH_ENGINES = {
76
114
  manager: 'julia-pkg',
77
115
  userArgv: ['<exe>', '-e', 'using Pkg; Pkg.add("__PKG__")'],
78
116
  uninstallArgv: ['<exe>', '-e', 'using Pkg; Pkg.rm("__PKG__")'],
117
+ systemUnsupportedReason: 'Julia 的 Pkg.add 装进当前活动环境 / 用户 depot(JULIA_DEPOT_PATH);系统级不是 Julia 的概念,本工具只出用户级计划',
79
118
  },
80
119
  userInstall: { windows: 'winget install --id Julialang.Julia', macos: 'brew install julia', linux: 'apt install julia' },
81
120
  },
@@ -84,7 +123,8 @@ export const MATH_ENGINES = {
84
123
  candidates: ['matlab'],
85
124
  versionArgv: ['-batch', 'disp(version)'], versionRe: '(\\d+\\.\\d+)',
86
125
  scriptArgv: ['-batch', "run('<script>')"], evalArgv: ['-batch', '<expr>'], stdinArgv: null, ext: '.m',
87
- probeCode: "t={'__QPKGS__'}; for i=1:numel(t); printf('%s:%d|',t{i},license('test',t{i})); end",
126
+ // round-7 (live): no `|`/`%` in any probe argv (a real host rejected such argv with a null spawn).
127
+ probeCode: "t={'__QPKGS__'}; for i=1:numel(t); if license('test',t{i}); disp([t{i} ' ok']); else; disp([t{i} ' missing']); end; end",
88
128
  packageProbe: { argv: ['-batch', '<probeCode>'], parse: 'pairs' },
89
129
  license: 'commercial', argErrorHints: ARG_ERROR_HINTS,
90
130
  licenseProbe: { argv: ['-batch', "disp(license('test','MATLAB'))"], okWhen: 'trim-1' },
@@ -96,7 +136,8 @@ export const MATH_ENGINES = {
96
136
  candidates: ['maple'],
97
137
  versionArgv: ['--version'], versionRe: '(\\d+\\.\\d+)',
98
138
  scriptArgv: ['-q', '<script>'], evalArgv: ['-q', '-c', '<expr>'], stdinArgv: null, ext: '.mpl',
99
- probeCode: 'for p in ["__PKGS__"] do try with(p) catch: printf("%s:missing|", p); next end try; printf("%s:ok|", p) end do',
139
+ // round-7 (live): `print` instead of printf so the argv carries no `|`/`%`.
140
+ probeCode: 'for p in ["__PKGS__"] do try with(p) catch: print(p, " missing"); next end try; print(p, " ok") end do',
100
141
  packageProbe: { argv: ['-q', '-c', '<probeCode>'], parse: 'pairs' },
101
142
  license: 'commercial', argErrorHints: ARG_ERROR_HINTS,
102
143
  licenseProbe: { argv: ['-q', '-c', 'printf("1")'], okWhen: 'exit-0' },
@@ -30,6 +30,7 @@ import {
30
30
  MATH_TOOL_DESCRIPTION,
31
31
  MATH_TOOL_SCHEMA,
32
32
  MATH_ARCHIVE_WORKFLOW_LINE,
33
+ MATH_SUBSTITUTION_RULE_LINE,
33
34
  MATH_PERSONA_TOOL_LINE,
34
35
  MATH_RULE_LINES,
35
36
  normalizeMathParams,
@@ -536,6 +537,11 @@ export function apply(ctx) {
536
537
  // **可选能力,按宿主实际情况声明**:宿主 fs 没有 listDir 就不给这个回调(模块据此跳过
537
538
  // "每项目 run 目录数 >200" 的保留检查,而不是每次运行都白问一次)。
538
539
  listDir: (typeof fs.listDir === 'function') ? mathListDir : undefined,
540
+ // round-7 (fix 2): DSH's own bundled runtimes (`<home>/.dsh/dsh-runtimes/*/dependencies/<engine>/`)
541
+ // as a LAST resort after PATH. Only generic roots are supplied here; the module globs the tree
542
+ // name (never `dsh-primary-runtime`) and only accepts the descriptor's own candidate names.
543
+ runtimeRoots: () => { const env = process.env.DSH_HOME; if (env) return [String(env)]; const home = String(process.env.HOME || process.env.USERPROFILE || ''); return home ? [home.replace(/[\\/]+$/, '') + '/.dsh'] : [] },
544
+ listDirAbs: async function (abs) { try { const t = await fsTarget(abs); const st = await fs.stat(t); if (!st) return []; return (await fs.listDir(t)) || [] } catch (e) { return [] } },
539
545
  writeText: async function (rel, text) { return await writeText(rel, text) },
540
546
  readText: async function (rel) { return await readText(rel) },
541
547
  exists: mathExists,
@@ -557,7 +563,15 @@ export function apply(ctx) {
557
563
  async function refreshMathProbe(force) {
558
564
  if (params.mathComputation === 'off') { mathProbe = null; mathProbeAt = 0; return null }
559
565
  if (!mathTool) return null
560
- try { mathProbe = await mathTool.probe(force ? { refresh: true } : undefined); mathProbeAt = now() } catch (e) { mathProbe = null }
566
+ try {
567
+ mathProbe = await mathTool.probe(force ? { refresh: true } : undefined)
568
+ mathProbeAt = now()
569
+ // 规则漂移自检(A 项):可用性行必须带"替代必须声明(诚实性)"这条规则。这里引用**常量**
570
+ // 而不是比对文本——模块以后改措辞不会误报,只有整条规则从 MATH_RULE_LINES 里消失才会响。
571
+ if (mathProbe && mathAvailabilityLine(mathProbe, 'zh', params.mathMode).indexOf(MATH_SUBSTITUTION_RULE_LINE) === -1) {
572
+ console.error('vibe-math-v2: 可用性行缺少替代声明规则(MATH_SUBSTITUTION_RULE_LINE)')
573
+ }
574
+ } catch (e) { mathProbe = null }
561
575
  return mathProbe
562
576
  }
563
577
  /** 心跳里的 TTL 刷新(每拍一次布尔判断,成本可忽略)。 */
@@ -4074,6 +4088,8 @@ export function apply(ctx) {
4074
4088
  mathProbe: function () { return mathProbe },
4075
4089
  // P2a:persona 两个文本块必须含的「归档→编辑→重跑」规则(文本取自共享模块常量,persona 不手抄)。
4076
4090
  mathArchiveWorkflowLine: MATH_ARCHIVE_WORKFLOW_LINE,
4091
+ // A 项:替代声明规则(文本由共享模块给出;persona 两块与每轮可用性行都必须带它)。
4092
+ mathSubstitutionRuleLine: MATH_SUBSTITUTION_RULE_LINE,
4077
4093
  leanQueueSize: function () { return leanQueue.length },
4078
4094
  leanJobsPublic: function () { const out = []; for (const j of leanJobs.values()) out.push(leanJobPublic(j)); return out },
4079
4095
  // childOwner 裁剪用:这个会话当前仍"可能再发 subagent/end"的 child(在册的 + 任务正在等的)。
@@ -68,6 +68,7 @@
68
68
  mode.
69
69
 
70
70
  - math_computation {op: probe|run|receipt|install, engine, mode: code|file|expr, …} — 先 probe 预检引擎/包/许可,再调引擎计算并把脚本与输出归档成可复核回执;缺引擎/缺包只报告与给安装指引/计划;shell 兜底不算归档。
71
+ - 替代必须声明(诚实性):当替代方案改变了**精确性或结论强度**时(精确符号解 → 数值近似、闭式解 → 采样/求积、改了精度/容差/假设、换了算法类),结论里**必须写明**,不得读起来像得到了原本(精确/所要求的)结果;拿不到精确结果就直说。
71
72
  - 归档→编辑→重跑:mode:'code' 的脚本原件在回执的 scriptPath(Computation/<id>/script.<ext>),你可以用普通文件工具打开并编辑它;编辑后用 mode:'file' 指向它重跑,会写出一份**新回执/新 attempt**(含新的 scriptHash)。**旧回执对修改后的代码无效**——报告里必须引用与当前代码哈希一致的那份回执;工具会在 scriptChanged / scriptChangedDuringRun 为 true 时显式告警。
72
73
 
73
74
  A /vibe slash command mirrors the main controls (/vibe start [override]|resume [override]|pause|abort|status|report|mode
@@ -159,6 +160,7 @@
159
160
  mode.
160
161
 
161
162
  - math_computation {op: probe|run|receipt|install, engine, mode: code|file|expr, …} — 先 probe 预检引擎/包/许可,再调引擎计算并把脚本与输出归档成可复核回执;缺引擎/缺包只报告与给安装指引/计划;shell 兜底不算归档。
163
+ - 替代必须声明(诚实性):当替代方案改变了**精确性或结论强度**时(精确符号解 → 数值近似、闭式解 → 采样/求积、改了精度/容差/假设、换了算法类),结论里**必须写明**,不得读起来像得到了原本(精确/所要求的)结果;拿不到精确结果就直说。
162
164
  - 归档→编辑→重跑:mode:'code' 的脚本原件在回执的 scriptPath(Computation/<id>/script.<ext>),你可以用普通文件工具打开并编辑它;编辑后用 mode:'file' 指向它重跑,会写出一份**新回执/新 attempt**(含新的 scriptHash)。**旧回执对修改后的代码无效**——报告里必须引用与当前代码哈希一致的那份回执;工具会在 scriptChanged / scriptChangedDuringRun 为 true 时显式告警。
163
165
 
164
166
  A /vibe slash command mirrors the main controls (/vibe start [override]|resume [override]|pause|abort|status|report|mode