micro-models-agent 2.11.0 → 2.12.0
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 +10 -0
- package/dist/assets/js/tabs.js +22 -3
- package/dist/cli/cache-line.js +1 -0
- package/dist/cli/command-suggest.js +5 -4
- package/dist/cli/commands.js +231 -122
- package/dist/cli/completer.js +132 -31
- package/dist/cli/index.js +1 -0
- package/dist/cli/json-payload.js +4 -4
- package/dist/cli/main.js +166 -61
- package/dist/cli/onboarding-commands.js +126 -0
- package/dist/cli/plugin-commands.js +2 -1
- package/dist/cli/relaunch.js +16 -13
- package/dist/cli/repl-commands-lsp.js +75 -0
- package/dist/cli/repl-commands-skills.js +105 -0
- package/dist/cli/repl-commands.js +589 -266
- package/dist/cli/repl.js +436 -177
- package/dist/cli/run-result.js +5 -6
- package/dist/cli/security-commands.js +37 -28
- package/dist/cli/setup-order.js +4 -55
- package/dist/cli/setup-prompt.js +3 -2
- package/dist/cli/setup.js +27 -107
- package/dist/cli/web-command.js +98 -0
- package/dist/config/budget.js +5 -5
- package/dist/config/config.js +103 -96
- package/dist/config/defaults.js +38 -8
- package/dist/config/domains.js +24 -27
- package/dist/config/env.js +46 -0
- package/dist/config/experts.js +2 -0
- package/dist/config/index.js +1 -0
- package/dist/config/paths.js +56 -0
- package/dist/config/redact.js +44 -0
- package/dist/config/registry-extra.js +334 -0
- package/dist/config/registry.js +584 -0
- package/dist/config/security.js +35 -36
- package/dist/config/timeouts.js +74 -0
- package/dist/config/utils.js +16 -15
- package/dist/core/agent/artifact-progress.js +59 -0
- package/dist/core/agent/artifact-resolve.js +79 -0
- package/dist/core/agent/audit-gate.js +7 -3
- package/dist/core/agent/compaction.js +2 -2
- package/dist/core/agent/constants.js +33 -4
- package/dist/core/agent/context-log.js +454 -0
- package/dist/core/agent/context-renderer.js +5 -0
- package/dist/core/agent/critic-gate.js +132 -0
- package/dist/core/agent/hallucination-gate.js +148 -38
- package/dist/core/agent/loop-state.js +15 -0
- package/dist/core/agent/prefix-monitor.js +1 -1
- package/dist/core/agent/reasoning-resolver.js +10 -1
- package/dist/core/agent/token-tracker.js +7 -4
- package/dist/core/agent/tool-batch.js +93 -18
- package/dist/core/agent/tool-images.js +18 -0
- package/dist/core/agent/tool-output.js +65 -11
- package/dist/core/agent/tool-pairing.js +60 -0
- package/dist/core/agent-moe.js +25 -24
- package/dist/core/agent.js +429 -108
- package/dist/core/bootstrap/agent-phase.js +66 -0
- package/dist/core/bootstrap/config-phase.js +86 -0
- package/dist/core/bootstrap/modules-phase.js +269 -0
- package/dist/core/bootstrap/provider-phase.js +183 -0
- package/dist/core/bootstrap/session-phase.js +204 -0
- package/dist/core/bootstrap/state.js +94 -0
- package/dist/core/bootstrap/workspace-phase.js +115 -0
- package/dist/core/bootstrap.js +92 -660
- package/dist/core/crash-handler.js +17 -7
- package/dist/core/environment.js +37 -12
- package/dist/core/host-plan.js +43 -0
- package/dist/core/host.js +23 -0
- package/dist/core/index.js +1 -0
- package/dist/core/prompt-builder.js +17 -1
- package/dist/core/prompt-overflow.js +42 -43
- package/dist/core/session-logger.js +122 -30
- package/dist/core/system-prompt.js +117 -0
- package/dist/core/version.js +6 -4
- package/dist/core/web-host.js +34 -0
- package/dist/core/workspace.js +19 -15
- package/dist/i18n/index.js +37 -3
- package/dist/index.js +7 -3
- package/dist/llm/image-utils.js +55 -64
- package/dist/llm/llm-errors.js +9 -0
- package/dist/llm/model-loader.js +10 -32
- package/dist/llm/models-dev.js +121 -0
- package/dist/llm/openai-compat.js +146 -73
- package/dist/llm/orchestrator.js +33 -11
- package/dist/llm/provider-budget.js +2 -2
- package/dist/llm/provider-context.js +233 -0
- package/dist/llm/provider.js +1 -1
- package/dist/llm/response.js +5 -0
- package/dist/llm/token-counter.js +27 -11
- package/dist/logger/app-logger.js +48 -22
- package/dist/logger/file-log.js +28 -19
- package/dist/logger/index.js +1 -0
- package/dist/main.js +273 -47
- package/dist/migration/backup.js +14 -3
- package/dist/migration/detect.js +12 -3
- package/dist/migration/index.js +1 -0
- package/dist/modules/artifacts/store.js +9 -8
- package/dist/modules/browser/actions.js +6 -0
- package/dist/modules/browser/bridge-client.js +14 -12
- package/dist/modules/browser/bridge-path.js +4 -4
- package/dist/modules/browser/console-buffer.js +37 -0
- package/dist/modules/browser/cookie-store.js +5 -0
- package/dist/modules/browser/driver-types.js +1 -0
- package/dist/modules/browser/driver.js +19 -11
- package/dist/modules/browser/index.js +3 -1
- package/dist/modules/browser/module.js +2 -1
- package/dist/modules/browser/session.js +10 -30
- package/dist/modules/browser/snapshot.js +19 -13
- package/dist/modules/browser/types.js +1 -0
- package/dist/modules/certification/cli.js +28 -20
- package/dist/modules/certification/fact-checker.js +9 -1
- package/dist/modules/certification/loader.js +9 -2
- package/dist/modules/certification/manifest.js +83 -21
- package/dist/modules/certification/runner.js +23 -13
- package/dist/modules/certification/scenarios.js +20 -20
- package/dist/modules/certification/syntax-scenarios.js +1 -2
- package/dist/modules/context/chunk-query.js +11 -9
- package/dist/modules/context/fact-extractor.js +37 -39
- package/dist/modules/context/index.js +1 -0
- package/dist/modules/context/manager.js +106 -80
- package/dist/modules/critic/client.js +176 -0
- package/dist/modules/critic/evidence.js +81 -0
- package/dist/modules/critic/provider.js +45 -0
- package/dist/modules/critic/tools.js +78 -0
- package/dist/modules/critic/types.js +1 -0
- package/dist/modules/execution/audit-runners.js +28 -34
- package/dist/modules/execution/auditor.js +53 -49
- package/dist/modules/execution/execution-plugin.js +142 -102
- package/dist/modules/execution/index.js +1 -1
- package/dist/modules/execution/input-from.js +37 -13
- package/dist/modules/execution/module.js +368 -191
- package/dist/modules/execution/moe-executor.js +53 -26
- package/dist/modules/execution/plan-actions.js +320 -202
- package/dist/modules/execution/plan-checks.js +35 -0
- package/dist/modules/execution/plan-coverage.js +36 -33
- package/dist/modules/execution/plan-steps.js +11 -3
- package/dist/modules/execution/plan-store.js +83 -17
- package/dist/modules/execution/plan-tool.js +89 -35
- package/dist/modules/execution/plan-validator.js +30 -10
- package/dist/modules/execution/planner.js +22 -13
- package/dist/modules/execution/stuck-detector.js +196 -93
- package/dist/modules/execution/tracker.js +22 -8
- package/dist/modules/execution/verifier.js +69 -48
- package/dist/modules/execution/windows-commands.js +12 -12
- package/dist/modules/hallucination/artifact-claim.js +93 -0
- package/dist/modules/hallucination/confidence.js +13 -11
- package/dist/modules/hallucination/consistency.js +10 -2
- package/dist/modules/hallucination/detector.js +10 -5
- package/dist/modules/hallucination/factual.js +43 -26
- package/dist/modules/hallucination/index.js +1 -0
- package/dist/modules/hallucination/js-identifiers.js +44 -45
- package/dist/modules/hallucination/llm-judge.js +17 -12
- package/dist/modules/hallucination/success-claim.js +59 -0
- package/dist/modules/indexer/cache.js +52 -4
- package/dist/modules/indexer/index.js +1 -0
- package/dist/modules/indexer/map-command.js +2 -4
- package/dist/modules/indexer/map-select.js +16 -16
- package/dist/modules/indexer/module.js +47 -12
- package/dist/modules/indexer/project-profile.js +8 -7
- package/dist/modules/indexer/symbols.js +15 -15
- package/dist/modules/indexer/walker.js +159 -29
- package/dist/modules/lsp/check-tool.js +7 -5
- package/dist/modules/lsp/client.js +39 -39
- package/dist/modules/lsp/command.js +17 -24
- package/dist/modules/lsp/config.js +12 -11
- package/dist/modules/lsp/index.js +1 -0
- package/dist/modules/lsp/module.js +48 -46
- package/dist/modules/lsp/probe.js +13 -14
- package/dist/modules/lsp/project-root.js +14 -17
- package/dist/modules/lsp/startup-check.js +18 -16
- package/dist/modules/mcp/client.js +59 -62
- package/dist/modules/mcp/index.js +1 -0
- package/dist/modules/mcp/module.js +66 -37
- package/dist/modules/mcp/registry.js +5 -0
- package/dist/modules/memory/index.js +1 -0
- package/dist/modules/memory/module.js +12 -8
- package/dist/modules/memory/search.js +4 -1
- package/dist/modules/memory/store.js +40 -2
- package/dist/modules/onboarding/init.js +47 -0
- package/dist/modules/onboarding/meet.js +30 -0
- package/dist/modules/onboarding/mode.js +30 -0
- package/dist/modules/onboarding/prompts.js +43 -0
- package/dist/modules/pipelines/engine.js +10 -0
- package/dist/modules/pipelines/index.js +1 -0
- package/dist/modules/pipelines/parser.js +4 -1
- package/dist/modules/pipelines/template.js +4 -0
- package/dist/modules/plugins/builtin/lint-on-write.js +80 -67
- package/dist/modules/plugins/builtin/notify.js +2 -0
- package/dist/modules/plugins/index.js +1 -0
- package/dist/modules/plugins/loader.js +18 -3
- package/dist/modules/plugins/manager.js +37 -17
- package/dist/modules/pricing/index.js +10 -11
- package/dist/modules/pricing/prices.js +12 -12
- package/dist/modules/processes/index.js +1 -0
- package/dist/modules/processes/kill-tree.js +27 -31
- package/dist/modules/processes/registry.js +44 -25
- package/dist/modules/processes/runner.js +4 -4
- package/dist/modules/providers/capabilities.js +28 -0
- package/dist/modules/providers/create.js +3 -4
- package/dist/modules/providers/factory.js +7 -7
- package/dist/modules/providers/fallback.js +12 -12
- package/dist/modules/providers/health.js +4 -4
- package/dist/modules/providers/manager.js +50 -19
- package/dist/modules/providers/naming.js +15 -0
- package/dist/modules/providers/preflight.js +71 -0
- package/dist/modules/providers/presets.js +39 -8
- package/dist/modules/providers/registry.js +7 -2
- package/dist/modules/reasoning/policy.js +8 -6
- package/dist/modules/reasoning/probe.js +30 -25
- package/dist/modules/security/audit-log.js +19 -36
- package/dist/modules/security/audit-notifier.js +35 -75
- package/dist/modules/security/command-validator.js +99 -51
- package/dist/modules/security/content-scanner.js +8 -8
- package/dist/modules/security/data-sanitizer.js +9 -16
- package/dist/modules/security/encryption.js +32 -52
- package/dist/modules/security/index.js +2 -1
- package/dist/modules/security/network-validator.js +120 -43
- package/dist/modules/security/path-validator.js +61 -46
- package/dist/modules/security/protected-paths.js +73 -0
- package/dist/modules/security/rate-limiter.js +17 -49
- package/dist/modules/security/security-policies.js +25 -57
- package/dist/modules/security/session-encryption.js +32 -71
- package/dist/modules/security/session-isolation.js +15 -28
- package/dist/modules/session/auto-name.js +63 -0
- package/dist/modules/session/export.js +98 -0
- package/dist/modules/session/index.js +1 -0
- package/dist/modules/session/manager.js +79 -28
- package/dist/modules/session/module.js +4 -3
- package/dist/modules/session/store.js +57 -20
- package/dist/modules/setup/answers.js +35 -0
- package/dist/modules/setup/apply.js +79 -0
- package/dist/modules/setup/discovery.js +72 -0
- package/dist/modules/skills/index.js +1 -0
- package/dist/modules/skills/loader.js +9 -1
- package/dist/modules/skills/module.js +11 -0
- package/dist/modules/updater/changelog-reader.js +15 -16
- package/dist/modules/updater/checker.js +9 -4
- package/dist/modules/updater/dev-detect.js +7 -6
- package/dist/modules/updater/index.js +1 -0
- package/dist/modules/updater/module.js +17 -15
- package/dist/modules/user-profile/compressor.js +2 -0
- package/dist/modules/user-profile/index.js +1 -0
- package/dist/modules/user-profile/profile.js +10 -1
- package/dist/modules/webui/answer-api.js +29 -0
- package/dist/modules/webui/assets.js +50 -0
- package/dist/modules/webui/body.js +21 -0
- package/dist/modules/webui/commands-settings.js +209 -0
- package/dist/modules/webui/commands-shared.js +60 -0
- package/dist/modules/webui/commands.js +174 -0
- package/dist/modules/webui/config-api.js +134 -0
- package/dist/modules/webui/file-api.js +202 -0
- package/dist/modules/webui/forward.js +159 -0
- package/dist/modules/webui/history-api.js +112 -0
- package/dist/modules/webui/host-state.js +60 -0
- package/dist/modules/webui/i18n-api.js +9 -0
- package/dist/modules/webui/limits.js +6 -0
- package/dist/modules/webui/log-forward.js +20 -0
- package/dist/modules/webui/memory-commands.js +64 -0
- package/dist/modules/webui/model-cache.js +18 -0
- package/dist/modules/webui/module.js +148 -0
- package/dist/modules/webui/persist.js +24 -0
- package/dist/modules/webui/prompt-io.js +97 -0
- package/dist/modules/webui/providers-api.js +337 -0
- package/dist/modules/webui/providers-view.js +56 -0
- package/dist/modules/webui/reasoning-view.js +15 -0
- package/dist/modules/webui/run-agent.js +81 -0
- package/dist/modules/webui/server.js +284 -0
- package/dist/modules/webui/sessions-api.js +178 -0
- package/dist/modules/webui/settings-api.js +561 -0
- package/dist/modules/webui/setup-api.js +201 -0
- package/dist/modules/webui/state.js +74 -0
- package/dist/modules/webui/util.js +261 -0
- package/dist/output/bus.js +7 -2
- package/dist/output/channel.js +80 -28
- package/dist/output/format.js +2 -1
- package/dist/output/index.js +1 -0
- package/dist/output/json-sink.js +5 -3
- package/dist/output/machine.js +4 -3
- package/dist/output/session-sink.js +4 -4
- package/dist/tools/approve.js +4 -0
- package/dist/tools/attach-image.js +5 -4
- package/dist/tools/auto-fixer.js +26 -44
- package/dist/tools/auto-tags.js +83 -0
- package/dist/tools/bash.js +193 -116
- package/dist/tools/browser.js +76 -31
- package/dist/tools/chunk-query.js +14 -6
- package/dist/tools/create-dir.js +9 -5
- package/dist/tools/delete-file.js +9 -5
- package/dist/tools/download-file.js +32 -7
- package/dist/tools/edit-file.js +52 -14
- package/dist/tools/enable-tools.js +6 -6
- package/dist/tools/executor.js +132 -27
- package/dist/tools/file-info.js +3 -1
- package/dist/tools/filter-tools.js +3 -3
- package/dist/tools/glob-tool.js +4 -1
- package/dist/tools/grep-tool.js +13 -10
- package/dist/tools/hidden-tools-block.js +6 -6
- package/dist/tools/index.js +16 -8
- package/dist/tools/list-dir.js +4 -2
- package/dist/tools/load-skill.js +7 -0
- package/dist/tools/mcp-call.js +15 -4
- package/dist/tools/meet-done.js +14 -0
- package/dist/tools/move-file.js +14 -7
- package/dist/tools/path-utils.js +29 -29
- package/dist/tools/pipeline-run.js +29 -7
- package/dist/tools/preview.js +1 -1
- package/dist/tools/process-ids.js +31 -0
- package/dist/tools/process-kill.js +9 -16
- package/dist/tools/process-list.js +1 -0
- package/dist/tools/process-log.js +11 -16
- package/dist/tools/process-wait.js +63 -0
- package/dist/tools/prompt-io.js +4 -3
- package/dist/tools/question.js +172 -25
- package/dist/tools/read-file.js +55 -34
- package/dist/tools/recall.js +14 -8
- package/dist/tools/registry.js +6 -5
- package/dist/tools/remember.js +8 -4
- package/dist/tools/scope-request.js +11 -6
- package/dist/tools/search-history.js +5 -2
- package/dist/tools/session-info.js +2 -0
- package/dist/tools/set-thinking.js +8 -4
- package/dist/tools/subagent.js +59 -39
- package/dist/tools/syntax-validator.js +292 -90
- package/dist/tools/user-input.js +22 -18
- package/dist/tools/web-browse.js +9 -3
- package/dist/tools/web-fetch.js +12 -23
- package/dist/tools/web-search.js +7 -5
- package/dist/tools/write-file.js +45 -15
- package/dist/ui/action-log.js +13 -0
- package/dist/ui/box.js +4 -3
- package/dist/ui/colors.js +2 -0
- package/dist/ui/diff.js +6 -5
- package/dist/ui/index.js +1 -0
- package/dist/ui/line-editor.js +230 -122
- package/dist/ui/line-math.js +10 -2
- package/dist/ui/md-formatter.js +57 -37
- package/dist/ui/output.js +8 -3
- package/dist/ui/plan-view.js +21 -10
- package/dist/ui/renderer.js +393 -67
- package/dist/ui/spinner.js +16 -5
- package/dist/ui/table.js +15 -17
- package/dist/ui/theme.js +143 -0
- package/dist/utils/child-run.js +20 -0
- package/dist/utils/error.js +1 -1
- package/dist/utils/index.js +2 -0
- package/dist/utils/retry.js +2 -2
- package/dist/utils/truncate.js +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,9 @@
|
|
|
1
|
+
// CLI-команды сертификации: прогон сценариев, статусы, список и снятие меток.
|
|
1
2
|
import { rmSync, writeFileSync } from "fs";
|
|
2
3
|
import { join, dirname } from "path";
|
|
3
4
|
import { fileURLToPath } from "url";
|
|
4
5
|
import { existsSync, readFileSync } from "fs";
|
|
6
|
+
import { projectMmaDir } from "../../config/paths";
|
|
5
7
|
import { t } from "../../i18n/index";
|
|
6
8
|
import { pc } from "../../ui/colors";
|
|
7
9
|
import { loadScenarios, filterByTags, filterByScenarios, unknownScenarioIds } from "./loader";
|
|
@@ -20,21 +22,26 @@ function readVersion() {
|
|
|
20
22
|
return raw.version;
|
|
21
23
|
}
|
|
22
24
|
catch {
|
|
23
|
-
//
|
|
25
|
+
// Битый package.json — откат на версию по умолчанию
|
|
24
26
|
}
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
return "0.0.0";
|
|
28
30
|
}
|
|
31
|
+
/** Разбирает строку тегов через запятую в список `CertTag`. */
|
|
29
32
|
export function parseTags(s) {
|
|
30
33
|
return s
|
|
31
34
|
.split(",")
|
|
32
35
|
.map((x) => x.trim())
|
|
33
36
|
.filter(Boolean);
|
|
34
37
|
}
|
|
38
|
+
/**
|
|
39
|
+
* Прогоняет выбранные сценарии на модели и сохраняет запись в манифест.
|
|
40
|
+
* Частичный прогон (по id) мержится с предыдущей записью.
|
|
41
|
+
*/
|
|
35
42
|
export async function certify(opts) {
|
|
36
43
|
const providerUrl = opts.providerUrl || opts.config.provider.baseUrl;
|
|
37
|
-
const { scenarios, errors } = loadScenarios(join(opts.projectDir, "
|
|
44
|
+
const { scenarios, errors } = loadScenarios(join(projectMmaDir(opts.projectDir), "certification", "scenarios"));
|
|
38
45
|
for (const e of errors)
|
|
39
46
|
getDefaultChannel().writeLine(pc.yellow(` ${e}`), "stderr");
|
|
40
47
|
let selected = filterByTags(scenarios, opts.tags);
|
|
@@ -49,10 +56,9 @@ export async function certify(opts) {
|
|
|
49
56
|
process.exitCode = 1;
|
|
50
57
|
return;
|
|
51
58
|
}
|
|
52
|
-
//
|
|
53
|
-
//
|
|
54
|
-
//
|
|
55
|
-
// selection.
|
|
59
|
+
// Точечный перепрогон выбирает из ВСЕХ загруженных сценариев (объединение
|
|
60
|
+
// тегов), а не из отфильтрованного по тегам подмножества — иначе перепрогон
|
|
61
|
+
// security-сценария с дефолтными core-тегами молча давал пустую выборку.
|
|
56
62
|
selected = filterByScenarios(scenarios, opts.scenarios);
|
|
57
63
|
}
|
|
58
64
|
if (selected.length === 0) {
|
|
@@ -62,8 +68,8 @@ export async function certify(opts) {
|
|
|
62
68
|
}
|
|
63
69
|
const manifest = readMergedManifest(opts.projectDir);
|
|
64
70
|
const existing = manifest.certifications.find((e) => e.model === opts.name && e.providerUrl === providerUrl);
|
|
65
|
-
//
|
|
66
|
-
// (
|
|
71
|
+
// Полный перепрогон перезаписывает запись и требует --force; частичный
|
|
72
|
+
// прогон (по id сценариев) по определению — инкрементальное обновление.
|
|
67
73
|
if (existing && !opts.force && !isPartial) {
|
|
68
74
|
getDefaultChannel().writeLine(pc.yellow(t("cli.cert_exists", { model: opts.name })), "stderr");
|
|
69
75
|
getDefaultChannel().writeLine(pc.yellow(t("cli.cert_exists_hint")), "stderr");
|
|
@@ -71,7 +77,7 @@ export async function certify(opts) {
|
|
|
71
77
|
return;
|
|
72
78
|
}
|
|
73
79
|
getDefaultChannel().writeLine(t("cli.cert_started", { model: opts.name, provider: providerUrl }));
|
|
74
|
-
const sandboxBase = join(process.cwd(), "
|
|
80
|
+
const sandboxBase = join(projectMmaDir(process.cwd()), "certification");
|
|
75
81
|
const results = [];
|
|
76
82
|
const total = selected.length;
|
|
77
83
|
let idx = 0;
|
|
@@ -116,13 +122,13 @@ export async function certify(opts) {
|
|
|
116
122
|
/* ignore */
|
|
117
123
|
}
|
|
118
124
|
}
|
|
119
|
-
//
|
|
125
|
+
// Частичный прогон: сохраняем прежние результаты неперегнанных сценариев.
|
|
120
126
|
const runIds = new Set(selected.map((s) => s.id));
|
|
121
127
|
const finalResults = isPartial && existing ? mergePartialResults(results, existing.results, runIds) : results;
|
|
122
128
|
const suite = summarize(finalResults);
|
|
123
|
-
//
|
|
124
|
-
// mmaVersion —
|
|
125
|
-
//
|
|
129
|
+
// Только прогон, покрывший ВСЕ сценарии набора, вправе обновить
|
|
130
|
+
// mmaVersion — частичный оставляет большинство результатов от старого MMA,
|
|
131
|
+
// и штамп текущей версии выдавал бы их за свежую сертификацию.
|
|
126
132
|
const ranEntireSuite = scenarios.every((s) => runIds.has(s.id));
|
|
127
133
|
const entry = {
|
|
128
134
|
model: opts.name,
|
|
@@ -132,9 +138,9 @@ export async function certify(opts) {
|
|
|
132
138
|
suite,
|
|
133
139
|
results: finalResults,
|
|
134
140
|
};
|
|
135
|
-
//
|
|
136
|
-
//
|
|
137
|
-
//
|
|
141
|
+
// Сертификации привязаны к паре (модель, providerUrl) — это машинный, а не
|
|
142
|
+
// проектный скоуп: храним в глобальном манифесте, чтобы метки следовали
|
|
143
|
+
// за пользователем в любой каталог.
|
|
138
144
|
upsertCertification(entry);
|
|
139
145
|
getDefaultChannel().writeLine(t("cli.cert_done", {
|
|
140
146
|
passed: String(suite.passed),
|
|
@@ -149,9 +155,10 @@ export async function certify(opts) {
|
|
|
149
155
|
else {
|
|
150
156
|
getDefaultChannel().writeLine(pc.yellow(`\n⚠ ${opts.name} is NOT certified — all scenarios must pass`));
|
|
151
157
|
}
|
|
152
|
-
//
|
|
158
|
+
// Файл отчёта пишется всегда
|
|
153
159
|
writeReport(entry, opts.projectDir);
|
|
154
160
|
}
|
|
161
|
+
/** Печатает статус сертификации модели (провайдер, версия, сводка, сценарии). */
|
|
155
162
|
export async function certStatus(name, config, projectDir) {
|
|
156
163
|
const m = readMergedManifest(projectDir);
|
|
157
164
|
const providerUrl = config.provider.baseUrl;
|
|
@@ -167,6 +174,7 @@ export async function certStatus(name, config, projectDir) {
|
|
|
167
174
|
getDefaultChannel().writeLine(`Status: ${status}`);
|
|
168
175
|
printResults(entry.results);
|
|
169
176
|
}
|
|
177
|
+
/** Печатает все записи манифеста (модель, провайдер, версия, счёт). */
|
|
170
178
|
export async function certList(projectDir) {
|
|
171
179
|
const m = readMergedManifest(projectDir);
|
|
172
180
|
if (m.certifications.length === 0) {
|
|
@@ -178,6 +186,7 @@ export async function certList(projectDir) {
|
|
|
178
186
|
getDefaultChannel().writeLine(` ${mark} ${e.model} ${pc.dim(e.providerUrl)} ${e.mmaVersion} ${e.certifiedAt.slice(0, 10)} ${e.suite.passed}/${e.suite.total} pass`);
|
|
179
187
|
}
|
|
180
188
|
}
|
|
189
|
+
/** Удаляет запись о сертификации модели из глобального и проектного манифестов. */
|
|
181
190
|
export async function uncertify(name, config, projectDir) {
|
|
182
191
|
const removed = removeCertification(name, config.provider.baseUrl, {
|
|
183
192
|
projectDir,
|
|
@@ -196,9 +205,8 @@ function summarize(results) {
|
|
|
196
205
|
};
|
|
197
206
|
}
|
|
198
207
|
/**
|
|
199
|
-
*
|
|
200
|
-
*
|
|
201
|
-
* are preserved verbatim.
|
|
208
|
+
* Сливает результаты частичного прогона с прежней сертификацией: свежие
|
|
209
|
+
* заменяют старые по id сценария; неперегнанные сохраняются как есть.
|
|
202
210
|
*/
|
|
203
211
|
export function mergePartialResults(fresh, previous, rerunIds) {
|
|
204
212
|
const preserved = previous.filter((r) => !rerunIds.has(r.id));
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
// Проверка результатов сценария в песочнице: файлы, вывод, код выхода.
|
|
1
2
|
import { existsSync, readFileSync, statSync } from "fs";
|
|
2
3
|
import { join } from "path";
|
|
4
|
+
/**
|
|
5
|
+
* Прогоняет проверки по состоянию песочницы.
|
|
6
|
+
* Возвращает общий вердикт и описания провалов.
|
|
7
|
+
*/
|
|
3
8
|
export function checkSandbox(sandboxDir, checks, exitCode, output) {
|
|
4
9
|
const failures = [];
|
|
5
10
|
for (const check of checks) {
|
|
@@ -14,7 +19,10 @@ function runCheck(sandboxDir, check, exitCode, output) {
|
|
|
14
19
|
case "exitCode":
|
|
15
20
|
return exitCode === (check.code ?? 0);
|
|
16
21
|
case "outputContains":
|
|
17
|
-
|
|
22
|
+
// Без учёта регистра: security-маркер выводится капсом ("[SECURITY BLOCKED]"),
|
|
23
|
+
// а строгое сравнение заставляло security-сценарии зависеть от того,
|
|
24
|
+
// продублирует ли модель слово "security" строчными.
|
|
25
|
+
return output.toLowerCase().includes(check.text.toLowerCase());
|
|
18
26
|
case "fileExists":
|
|
19
27
|
return isFile(join(sandboxDir, check.path));
|
|
20
28
|
case "fileNotExists":
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// Загрузка сценариев сертификации: встроенные плюс пользовательские YAML из каталога.
|
|
1
2
|
import { existsSync, readdirSync, readFileSync } from "fs";
|
|
2
3
|
import { join } from "path";
|
|
3
4
|
import { parse as parseYaml } from "yaml";
|
|
@@ -12,6 +13,7 @@ const CHECK_TYPES = [
|
|
|
12
13
|
"exitCode",
|
|
13
14
|
"outputContains",
|
|
14
15
|
];
|
|
16
|
+
/** Проверяет сценарий, возвращает список ошибок (пусто — валиден). */
|
|
15
17
|
export function validateScenario(s) {
|
|
16
18
|
const errors = [];
|
|
17
19
|
const isSkip = s.mode === "skip";
|
|
@@ -54,6 +56,10 @@ export function validateScenario(s) {
|
|
|
54
56
|
}
|
|
55
57
|
return errors;
|
|
56
58
|
}
|
|
59
|
+
/**
|
|
60
|
+
* Загружает встроенные сценарии и пользовательские YAML из `userDir`.
|
|
61
|
+
* Битые описания отбрасываются с записью ошибки в `errors`.
|
|
62
|
+
*/
|
|
57
63
|
export function loadScenarios(userDir) {
|
|
58
64
|
const errors = [];
|
|
59
65
|
const scenarios = [];
|
|
@@ -102,18 +108,19 @@ function normalizeScenario(data, file) {
|
|
|
102
108
|
config: typeof d.config === "object" && d.config !== null ? d.config : undefined,
|
|
103
109
|
};
|
|
104
110
|
}
|
|
111
|
+
/** Фильтрует сценарии по тегам; без тегов оставляет только `core`. */
|
|
105
112
|
export function filterByTags(scenarios, tags) {
|
|
106
113
|
if (!tags || tags.length === 0) {
|
|
107
114
|
return scenarios.filter((s) => s.tags.includes("core"));
|
|
108
115
|
}
|
|
109
116
|
return scenarios.filter((s) => s.tags.some((t) => tags.includes(t)));
|
|
110
117
|
}
|
|
111
|
-
/**
|
|
118
|
+
/** Оставляет сценарии с id из списка (точное совпадение без учёта регистра). */
|
|
112
119
|
export function filterByScenarios(scenarios, ids) {
|
|
113
120
|
const wanted = new Set(ids.map((id) => id.toLowerCase()));
|
|
114
121
|
return scenarios.filter((s) => wanted.has(s.id.toLowerCase()));
|
|
115
122
|
}
|
|
116
|
-
/**
|
|
123
|
+
/** Возвращает запрошенные id, которых нет среди загруженных сценариев. */
|
|
117
124
|
export function unknownScenarioIds(scenarios, ids) {
|
|
118
125
|
const known = new Set(scenarios.map((s) => s.id.toLowerCase()));
|
|
119
126
|
return ids.filter((id) => !known.has(id.toLowerCase()));
|
|
@@ -1,17 +1,23 @@
|
|
|
1
|
+
// Манифест сертификации: проектный и глобальный (per-user) файлы, мерж и синк bundled-копии.
|
|
1
2
|
import { existsSync, readFileSync, mkdirSync, writeFileSync } from "fs";
|
|
2
3
|
import { dirname, join } from "path";
|
|
3
4
|
import { fileURLToPath } from "url";
|
|
4
5
|
import { homedir } from "os";
|
|
6
|
+
import { MMA_DIR_NAME } from "../../config/paths";
|
|
7
|
+
import { readEnv } from "../../config/env";
|
|
8
|
+
/** Путь к проектному манифесту внутри каталога проекта. */
|
|
5
9
|
export function manifestPath(projectDir) {
|
|
6
10
|
return join(projectDir, "certification", "certifications.json");
|
|
7
11
|
}
|
|
8
|
-
/**
|
|
12
|
+
/** Каталог глобального (per-user) манифеста. Переопределяется для тестов. */
|
|
9
13
|
export function globalManifestDir(override) {
|
|
10
|
-
return override ||
|
|
14
|
+
return override || readEnv("CERT_HOME") || join(homedir(), MMA_DIR_NAME);
|
|
11
15
|
}
|
|
16
|
+
/** Путь к глобальному манифесту. */
|
|
12
17
|
export function globalManifestPath(override) {
|
|
13
18
|
return join(globalManifestDir(override), "certifications.json");
|
|
14
19
|
}
|
|
20
|
+
/** Читает проектный манифест; битый/отсутствующий даёт пустой. */
|
|
15
21
|
export function readManifest(projectDir) {
|
|
16
22
|
const path = manifestPath(projectDir);
|
|
17
23
|
try {
|
|
@@ -21,15 +27,17 @@ export function readManifest(projectDir) {
|
|
|
21
27
|
}
|
|
22
28
|
}
|
|
23
29
|
catch {
|
|
24
|
-
/*
|
|
30
|
+
/* битый манифест → начинаем с чистого */
|
|
25
31
|
}
|
|
26
32
|
return { version: 1, certifications: [] };
|
|
27
33
|
}
|
|
34
|
+
/** Сохраняет проектный манифест (каталог создаётся). */
|
|
28
35
|
export function saveManifest(m, projectDir) {
|
|
29
36
|
const path = manifestPath(projectDir);
|
|
30
37
|
mkdirSync(join(projectDir, "certification"), { recursive: true });
|
|
31
38
|
writeFileSync(path, JSON.stringify(m, null, 2), "utf-8");
|
|
32
39
|
}
|
|
40
|
+
/** Читает глобальный манифест; битый/отсутствующий даёт пустой. */
|
|
33
41
|
export function readGlobalManifest(override) {
|
|
34
42
|
const path = globalManifestPath(override);
|
|
35
43
|
try {
|
|
@@ -39,10 +47,11 @@ export function readGlobalManifest(override) {
|
|
|
39
47
|
}
|
|
40
48
|
}
|
|
41
49
|
catch {
|
|
42
|
-
/*
|
|
50
|
+
/* битый глобальный манифест → начинаем с чистого */
|
|
43
51
|
}
|
|
44
52
|
return { version: 1, certifications: [] };
|
|
45
53
|
}
|
|
54
|
+
/** Сохраняет глобальный манифест. */
|
|
46
55
|
export function saveGlobalManifest(m, override) {
|
|
47
56
|
const dir = globalManifestDir(override);
|
|
48
57
|
mkdirSync(dir, { recursive: true });
|
|
@@ -50,17 +59,26 @@ export function saveGlobalManifest(m, override) {
|
|
|
50
59
|
}
|
|
51
60
|
const certKey = (e) => `${e.model}::${e.providerUrl}`;
|
|
52
61
|
/**
|
|
53
|
-
*
|
|
54
|
-
*
|
|
62
|
+
* Глобальный + проектный манифесты, сведённые по (model, providerUrl). Побеждает
|
|
63
|
+
* БОЛЕЕ НОВАЯ запись (сначала mmaVersion, затем certifiedAt); легаси-проектный
|
|
64
|
+
* манифест свежую глобальную сертификацию больше не затеняет.
|
|
55
65
|
*/
|
|
56
66
|
export function readMergedManifest(projectDir, override) {
|
|
57
67
|
const merged = new Map();
|
|
58
68
|
for (const e of readGlobalManifest(override).certifications)
|
|
59
69
|
merged.set(certKey(e), e);
|
|
60
|
-
for (const e of readManifest(projectDir).certifications)
|
|
61
|
-
|
|
70
|
+
for (const e of readManifest(projectDir).certifications) {
|
|
71
|
+
const key = certKey(e);
|
|
72
|
+
const existing = merged.get(key);
|
|
73
|
+
if (!existing || isEntryNewer(e, existing))
|
|
74
|
+
merged.set(key, e);
|
|
75
|
+
}
|
|
62
76
|
return { version: 1, certifications: [...merged.values()] };
|
|
63
77
|
}
|
|
78
|
+
/**
|
|
79
|
+
* Добавляет/обновляет запись в глобальном манифесте по ключу (model, providerUrl).
|
|
80
|
+
* Возвращает обновлённый манифест.
|
|
81
|
+
*/
|
|
64
82
|
export function upsertCertification(entry, override) {
|
|
65
83
|
const m = readGlobalManifest(override);
|
|
66
84
|
const idx = m.certifications.findIndex((e) => certKey(e) === certKey(entry));
|
|
@@ -71,6 +89,10 @@ export function upsertCertification(entry, override) {
|
|
|
71
89
|
saveGlobalManifest(m, override);
|
|
72
90
|
return m;
|
|
73
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Удаляет запись из глобального и легаси-проектного манифестов.
|
|
94
|
+
* Возвращает флаги, откуда реально удалили.
|
|
95
|
+
*/
|
|
74
96
|
export function removeCertification(model, providerUrl, opts) {
|
|
75
97
|
const key = `${model}::${providerUrl}`;
|
|
76
98
|
const g = readGlobalManifest(opts?.globalDir);
|
|
@@ -79,7 +101,7 @@ export function removeCertification(model, providerUrl, opts) {
|
|
|
79
101
|
const removedGlobal = g.certifications.length !== beforeG;
|
|
80
102
|
if (removedGlobal)
|
|
81
103
|
saveGlobalManifest(g, opts?.globalDir);
|
|
82
|
-
//
|
|
104
|
+
// В легаси-проектных манифестах запись могла остаться — чистим и их.
|
|
83
105
|
let removedProject = false;
|
|
84
106
|
try {
|
|
85
107
|
const projectDir = opts?.projectDir ?? process.cwd();
|
|
@@ -92,16 +114,49 @@ export function removeCertification(model, providerUrl, opts) {
|
|
|
92
114
|
}
|
|
93
115
|
}
|
|
94
116
|
catch {
|
|
95
|
-
/*
|
|
117
|
+
/* проектного манифеста нет — нормально */
|
|
96
118
|
}
|
|
97
119
|
return { global: removedGlobal, project: removedProject };
|
|
98
120
|
}
|
|
121
|
+
/** True, если запись сделана не на текущей версии MMA (протухла). */
|
|
99
122
|
export function isStale(entry, currentVersion) {
|
|
100
123
|
return entry.mmaVersion !== currentVersion;
|
|
101
124
|
}
|
|
125
|
+
/** Numeric semver-ish comparison; non-numeric/missing parts count as 0. */
|
|
126
|
+
function compareVersions(a, b) {
|
|
127
|
+
const pa = String(a ?? "").split(".").map((n) => parseInt(n, 10) || 0);
|
|
128
|
+
const pb = String(b ?? "").split(".").map((n) => parseInt(n, 10) || 0);
|
|
129
|
+
const len = Math.max(pa.length, pb.length);
|
|
130
|
+
for (let i = 0; i < len; i++) {
|
|
131
|
+
const d = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
132
|
+
if (d !== 0)
|
|
133
|
+
return d > 0 ? 1 : -1;
|
|
134
|
+
}
|
|
135
|
+
return 0;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Действительно ли `candidate` новее `current` (сначала mmaVersion, затем
|
|
139
|
+
* certifiedAt)? Защита от даунгрейда свежей сертификации — и при синке
|
|
140
|
+
* bundled-манифеста, и при мерже легаси-проектного.
|
|
141
|
+
*/
|
|
142
|
+
function isEntryNewer(candidate, current) {
|
|
143
|
+
const v = compareVersions(candidate.mmaVersion, current.mmaVersion);
|
|
144
|
+
if (v !== 0)
|
|
145
|
+
return v > 0;
|
|
146
|
+
const ec = Date.parse(candidate.certifiedAt ?? "");
|
|
147
|
+
const ee = Date.parse(current.certifiedAt ?? "");
|
|
148
|
+
if (!Number.isNaN(ec) && !Number.isNaN(ee))
|
|
149
|
+
return ec > ee;
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
/** True, если в записи нет провалов и есть хоть один пройденный сценарий. */
|
|
102
153
|
export function isFullyPassed(entry) {
|
|
103
154
|
return entry.suite.failed === 0 && entry.suite.passed > 0;
|
|
104
155
|
}
|
|
156
|
+
/**
|
|
157
|
+
* Метка модели: `certified` (всё прошло на текущей версии), `stale` (запись от
|
|
158
|
+
* старой версии) или `none` (нет записи / есть провалы).
|
|
159
|
+
*/
|
|
105
160
|
export function getCertMark(model, providerUrl, currentVersion, projectDir, globalOverride) {
|
|
106
161
|
const m = readMergedManifest(projectDir, globalOverride);
|
|
107
162
|
const entry = m.certifications.find((e) => e.model === model && e.providerUrl === providerUrl);
|
|
@@ -116,9 +171,9 @@ function syncSnapshotPath(override) {
|
|
|
116
171
|
return join(globalManifestDir(override), "certifications.synced.json");
|
|
117
172
|
}
|
|
118
173
|
/**
|
|
119
|
-
*
|
|
120
|
-
* - dist/main.js
|
|
121
|
-
* -
|
|
174
|
+
* Ищет certifications.json, упакованный в установленный пакет MMA.
|
|
175
|
+
* - бандл dist/main.js: <dist>/certification/certifications.json (копирует copy-assets)
|
|
176
|
+
* - исходники: <repo-root>/certification/certifications.json
|
|
122
177
|
*/
|
|
123
178
|
export function bundledManifestPath() {
|
|
124
179
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
@@ -134,12 +189,12 @@ export function bundledManifestPath() {
|
|
|
134
189
|
return null;
|
|
135
190
|
}
|
|
136
191
|
/**
|
|
137
|
-
*
|
|
138
|
-
* ~/.mma/certifications.json.
|
|
139
|
-
*
|
|
140
|
-
*
|
|
141
|
-
*
|
|
142
|
-
*
|
|
192
|
+
* Вливает упакованный (поставляемый с пакетом) манифест в глобальный
|
|
193
|
+
* ~/.mma/certifications.json. Работает раз на старт процесса:
|
|
194
|
+
* bundled-файл при каждом обновлении пакета перезаписывает СВОИ записи;
|
|
195
|
+
* пользовательские сертификации под ДРУГИМИ ключами сохраняются. Снапшот
|
|
196
|
+
* сырого bundled-содержимого фиксирует, что уже синкнуто, чтобы между
|
|
197
|
+
* обновлениями ничего не переписывать.
|
|
143
198
|
*/
|
|
144
199
|
export function syncGlobalManifest(override, bundledPathOverride) {
|
|
145
200
|
try {
|
|
@@ -156,8 +211,15 @@ export function syncGlobalManifest(override, bundledPathOverride) {
|
|
|
156
211
|
const merged = new Map();
|
|
157
212
|
for (const e of current.certifications)
|
|
158
213
|
merged.set(certKey(e), e);
|
|
159
|
-
for (const e of bundled.certifications ?? [])
|
|
160
|
-
|
|
214
|
+
for (const e of bundled.certifications ?? []) {
|
|
215
|
+
const key = certKey(e);
|
|
216
|
+
const existing = merged.get(key);
|
|
217
|
+
// Не перезаписываем более свежую пользовательскую сертификацию старой
|
|
218
|
+
// bundled-копией (иначе запуск CLI затирает только что сделанный certify).
|
|
219
|
+
if (existing && !isEntryNewer(e, existing))
|
|
220
|
+
continue;
|
|
221
|
+
merged.set(key, e);
|
|
222
|
+
}
|
|
161
223
|
saveGlobalManifest({ version: 1, certifications: [...merged.values()] }, override);
|
|
162
224
|
mkdirSync(globalManifestDir(override), { recursive: true });
|
|
163
225
|
writeFileSync(snapshotPath, raw, "utf-8");
|
|
@@ -1,9 +1,16 @@
|
|
|
1
|
+
// Прогон сценариев сертификации: песочница на повтор, запуск MMA, проверки.
|
|
1
2
|
import { spawn } from "child_process";
|
|
2
|
-
import { existsSync, mkdirSync, rmSync, cpSync, writeFileSync, readdirSync, readFileSync } from "fs";
|
|
3
|
+
import { existsSync, mkdirSync, rmSync, cpSync, writeFileSync, readdirSync, readFileSync, } from "fs";
|
|
3
4
|
import { join, resolve, dirname, relative } from "path";
|
|
4
5
|
import { checkSandbox } from "./fact-checker";
|
|
5
6
|
import { killTree } from "../processes/kill-tree";
|
|
6
7
|
import { toForwardSlash } from "../../tools/path-utils";
|
|
8
|
+
import { projectMmaDir } from "../../config/paths";
|
|
9
|
+
import { MMA_ENV } from "../../config/env";
|
|
10
|
+
/**
|
|
11
|
+
* Прогоняет сценарий N повторов в изолированных песочницах.
|
|
12
|
+
* `pass`, когда прошли не меньше порога; при провале прикладывает диагностику.
|
|
13
|
+
*/
|
|
7
14
|
export async function runScenario(scenario, opts) {
|
|
8
15
|
if (scenario.mode === "skip") {
|
|
9
16
|
return {
|
|
@@ -39,19 +46,19 @@ export async function runScenario(scenario, opts) {
|
|
|
39
46
|
];
|
|
40
47
|
const env = {
|
|
41
48
|
...process.env,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
49
|
+
[MMA_ENV.MODEL]: opts.model,
|
|
50
|
+
[MMA_ENV.PROVIDER_BASEURL]: opts.providerUrl,
|
|
51
|
+
[MMA_ENV.CONTEXT_WINDOW]: String(opts.contextWindow ?? 32000),
|
|
45
52
|
};
|
|
46
53
|
if (opts.providerKey)
|
|
47
|
-
env.
|
|
48
|
-
//
|
|
54
|
+
env[MMA_ENV.PROVIDER_APIKEY] = opts.providerKey;
|
|
55
|
+
// Пишем cert-конфиг, если сценарий объявил оверрайды
|
|
49
56
|
if (scenario.config && opts.baseConfig) {
|
|
50
57
|
const merged = deepMergeAny(opts.baseConfig, scenario.config);
|
|
51
|
-
const certConfigDir =
|
|
58
|
+
const certConfigDir = projectMmaDir(sandbox);
|
|
52
59
|
mkdirSync(certConfigDir, { recursive: true });
|
|
53
60
|
writeFileSync(join(certConfigDir, "config.json"), JSON.stringify(merged, null, 2), "utf-8");
|
|
54
|
-
env.
|
|
61
|
+
env[MMA_ENV.CONFIG_DIR] = certConfigDir;
|
|
55
62
|
}
|
|
56
63
|
const res = await runner(env, opts.mmaRoot, args, timeoutMs);
|
|
57
64
|
output = `${res.stdout}\n${res.stderr}`;
|
|
@@ -108,10 +115,10 @@ function prepareSandbox(sandbox, scenario, mmaRoot) {
|
|
|
108
115
|
cpSync(src, dest);
|
|
109
116
|
}
|
|
110
117
|
}
|
|
111
|
-
/**
|
|
118
|
+
/** Собирает диагностику из проваленной песочницы для понятного фидбэка. */
|
|
112
119
|
export function collectDiagnostics(sandbox) {
|
|
113
120
|
const lines = [];
|
|
114
|
-
//
|
|
121
|
+
// Список созданных пользователем файлов (внутренности .mma пропускаем)
|
|
115
122
|
const files = listFiles(sandbox, sandbox);
|
|
116
123
|
if (files.length > 0) {
|
|
117
124
|
lines.push(` Files created: ${files.join(", ")}`);
|
|
@@ -119,8 +126,8 @@ export function collectDiagnostics(sandbox) {
|
|
|
119
126
|
else {
|
|
120
127
|
lines.push(" Files created: (none)");
|
|
121
128
|
}
|
|
122
|
-
//
|
|
123
|
-
const planPath = join(sandbox, "
|
|
129
|
+
// Читаем активный план, если есть
|
|
130
|
+
const planPath = join(projectMmaDir(sandbox), "plans", "active.json");
|
|
124
131
|
if (existsSync(planPath)) {
|
|
125
132
|
try {
|
|
126
133
|
const plan = JSON.parse(readFileSync(planPath, "utf-8"));
|
|
@@ -133,7 +140,7 @@ export function collectDiagnostics(sandbox) {
|
|
|
133
140
|
}
|
|
134
141
|
}
|
|
135
142
|
catch {
|
|
136
|
-
/*
|
|
143
|
+
/* битый план — пропускаем */
|
|
137
144
|
}
|
|
138
145
|
}
|
|
139
146
|
return lines.join("\n");
|
|
@@ -159,12 +166,14 @@ function listFiles(dir, root) {
|
|
|
159
166
|
}
|
|
160
167
|
return result;
|
|
161
168
|
}
|
|
169
|
+
/** Резолвит точку входа MMA: исходники в dev-дереве, иначе собранный бандл. */
|
|
162
170
|
export function resolveMmaEntry(mmaRoot) {
|
|
163
171
|
const dev = join(mmaRoot, "src", "cli", "main.ts");
|
|
164
172
|
if (existsSync(dev))
|
|
165
173
|
return dev;
|
|
166
174
|
return join(mmaRoot, "dist", "main.js");
|
|
167
175
|
}
|
|
176
|
+
/** Ищет корень MMA вверх от каталога (по package.json). */
|
|
168
177
|
export function findMmaRoot(fromDir) {
|
|
169
178
|
const candidates = [resolve(fromDir, "..", "..", ".."), resolve(fromDir, "..")];
|
|
170
179
|
for (const c of candidates) {
|
|
@@ -173,6 +182,7 @@ export function findMmaRoot(fromDir) {
|
|
|
173
182
|
}
|
|
174
183
|
return process.cwd();
|
|
175
184
|
}
|
|
185
|
+
/** Дефолтный раннер: спавнит MMA дочерним процессом с таймаутом и киллом дерева. */
|
|
176
186
|
export const defaultRunner = (env, cwd, args, timeoutMs) => new Promise((resolvePromise) => {
|
|
177
187
|
const child = spawn(process.execPath, args, {
|
|
178
188
|
cwd,
|