@bonesofspring/ai-rules 0.2.22 → 0.2.23
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 +8 -0
- package/README.md +6 -2
- package/bin/cli.js +32 -8
- package/bin/mavis-install.js +441 -0
- package/package.json +9 -2
- package/presets/_shared/core/meta/preset-pr-checklist.md +1 -0
- package/presets/_shared/core/meta/preset-twin-sync.md +16 -0
- package/presets/claude/android-kotlin/rules/tooling-and-review/preset-pr-checklist.md +1 -0
- package/presets/claude/android-kotlin/rules/tooling-and-review/preset-twin-sync.md +16 -0
- package/presets/claude/go/rules/tooling-and-review/preset-pr-checklist.md +1 -0
- package/presets/claude/go/rules/tooling-and-review/preset-twin-sync.md +16 -0
- package/presets/claude/ios-swift/rules/tooling-and-review/preset-pr-checklist.md +1 -0
- package/presets/claude/ios-swift/rules/tooling-and-review/preset-twin-sync.md +16 -0
- package/presets/claude/java/rules/tooling-and-review/preset-pr-checklist.md +1 -0
- package/presets/claude/java/rules/tooling-and-review/preset-twin-sync.md +16 -0
- package/presets/claude/mcp-ts/rules/tooling-and-review/preset-pr-checklist.md +1 -0
- package/presets/claude/mcp-ts/rules/tooling-and-review/preset-twin-sync.md +16 -0
- package/presets/claude/next/rules/tooling-and-review/preset-pr-checklist.md +1 -0
- package/presets/claude/next/rules/tooling-and-review/preset-twin-sync.md +16 -0
- package/presets/claude/nuxt/rules/tooling-and-review/preset-pr-checklist.md +1 -0
- package/presets/claude/nuxt/rules/tooling-and-review/preset-twin-sync.md +16 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-pr-checklist.md +1 -0
- package/presets/claude/php-hexagonal/rules/tooling-and-review/preset-twin-sync.md +16 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/preset-pr-checklist.md +1 -0
- package/presets/claude/php-laravel/rules/tooling-and-review/preset-twin-sync.md +16 -0
- package/presets/claude/svelte/rules/tooling-and-review/preset-pr-checklist.md +1 -0
- package/presets/claude/svelte/rules/tooling-and-review/preset-twin-sync.md +16 -0
- package/presets/cursor/android-kotlin/rules/preset-pr-checklist.mdc +1 -0
- package/presets/cursor/android-kotlin/rules/preset-twin-sync.mdc +16 -0
- package/presets/cursor/go/rules/preset-pr-checklist.mdc +1 -0
- package/presets/cursor/go/rules/preset-twin-sync.mdc +16 -0
- package/presets/cursor/ios-swift/rules/preset-pr-checklist.mdc +1 -0
- package/presets/cursor/ios-swift/rules/preset-twin-sync.mdc +16 -0
- package/presets/cursor/java/rules/preset-pr-checklist.mdc +1 -0
- package/presets/cursor/java/rules/preset-twin-sync.mdc +16 -0
- package/presets/cursor/mcp-ts/rules/preset-pr-checklist.mdc +1 -0
- package/presets/cursor/mcp-ts/rules/preset-twin-sync.mdc +16 -0
- package/presets/cursor/next/rules/preset-pr-checklist.mdc +1 -0
- package/presets/cursor/next/rules/preset-twin-sync.mdc +16 -0
- package/presets/cursor/nuxt/rules/preset-pr-checklist.mdc +1 -0
- package/presets/cursor/nuxt/rules/preset-twin-sync.mdc +16 -0
- package/presets/cursor/php-hexagonal/rules/preset-pr-checklist.mdc +1 -0
- package/presets/cursor/php-hexagonal/rules/preset-twin-sync.mdc +16 -0
- package/presets/cursor/php-laravel/rules/preset-pr-checklist.mdc +1 -0
- package/presets/cursor/php-laravel/rules/preset-twin-sync.mdc +16 -0
- package/presets/cursor/svelte/rules/preset-pr-checklist.mdc +1 -0
- package/presets/cursor/svelte/rules/preset-twin-sync.mdc +16 -0
- package/presets/mavis/README.md +60 -0
- package/presets/mavis/next/MAVIS.md +67 -0
- package/presets/mavis/next/MCP.md +36 -0
- package/presets/mavis/next/README.md +15 -0
- package/presets/mavis/next/REPO_AGENTS.md +94 -0
- package/presets/mavis/next/adapter-map.json +959 -0
- package/presets/mavis/next/agents/README.md +206 -0
- package/presets/mavis/next/agents/accessibility-reviewer.md +61 -0
- package/presets/mavis/next/agents/api-contract-reviewer.md +57 -0
- package/presets/mavis/next/agents/build-verifier.md +110 -0
- package/presets/mavis/next/agents/ci-investigator.md +63 -0
- package/presets/mavis/next/agents/code-reviewer.md +61 -0
- package/presets/mavis/next/agents/codebase-analyzer.md +21 -0
- package/presets/mavis/next/agents/debugger.md +80 -0
- package/presets/mavis/next/agents/feature-developer.md +101 -0
- package/presets/mavis/next/agents/migration-specialist.md +67 -0
- package/presets/mavis/next/agents/mockup-reviewer.md +53 -0
- package/presets/mavis/next/agents/openspec-author.md +157 -0
- package/presets/mavis/next/agents/performance-auditor.md +68 -0
- package/presets/mavis/next/agents/playwright-test-generator.md +28 -0
- package/presets/mavis/next/agents/playwright-test-healer.md +28 -0
- package/presets/mavis/next/agents/playwright-test-planner.md +21 -0
- package/presets/mavis/next/agents/qa-tester.md +52 -0
- package/presets/mavis/next/agents/security-reviewer.md +54 -0
- package/presets/mavis/next/agents/solution-architect.md +68 -0
- package/presets/mavis/next/agents/task-analyst.md +166 -0
- package/presets/mavis/next/agents/task-router.md +178 -0
- package/presets/mavis/next/agents/tech-writer.md +57 -0
- package/presets/mavis/next/agents/unit-test-generator.md +31 -0
- package/presets/mavis/next/agents/unit-test-healer.md +32 -0
- package/presets/mavis/next/agents/unit-test-planner.md +54 -0
- package/presets/mavis/next/commands/README.md +49 -0
- package/presets/mavis/next/commands/spec-start.md +24 -0
- package/presets/mavis/next/commands/task-continue.md +50 -0
- package/presets/mavis/next/commands/task.md +50 -0
- package/presets/mavis/next/commands/technical-retro.md +80 -0
- package/presets/mavis/next/hooks/README.md +22 -0
- package/presets/mavis/next/hooks/chain-team-phases.sh +845 -0
- package/presets/mavis/next/mcp.json +19 -0
- package/presets/mavis/next/rules/README.md +16 -0
- package/presets/mavis/next/rules/agent-team-intake.md +11 -0
- package/presets/mavis/next/rules/agent-team-orchestrator.md +210 -0
- package/presets/mavis/next/rules/ai-local-overlay.md +37 -0
- package/presets/mavis/next/rules/anti-sycophancy-discipline.md +23 -0
- package/presets/mavis/next/rules/api-services.md +72 -0
- package/presets/mavis/next/rules/architecture-boundaries-ui.md +9 -0
- package/presets/mavis/next/rules/architecture-boundaries.md +86 -0
- package/presets/mavis/next/rules/arrow-functions.md +25 -0
- package/presets/mavis/next/rules/code-quality-and-refactoring.md +40 -0
- package/presets/mavis/next/rules/code-review-mr.md +40 -0
- package/presets/mavis/next/rules/css-property-order-stylelint.md +5 -0
- package/presets/mavis/next/rules/design-guidance.md +99 -0
- package/presets/mavis/next/rules/feature-delivery-workflow.md +49 -0
- package/presets/mavis/next/rules/http-client.md +55 -0
- package/presets/mavis/next/rules/layer-barrel-exports.md +68 -0
- package/presets/mavis/next/rules/mcp-usage.md +86 -0
- package/presets/mavis/next/rules/mockup-review.md +107 -0
- package/presets/mavis/next/rules/navigation-router-stack.md +56 -0
- package/presets/mavis/next/rules/navigation-router-ui.md +10 -0
- package/presets/mavis/next/rules/next-app-core.md +29 -0
- package/presets/mavis/next/rules/next-app-router.md +44 -0
- package/presets/mavis/next/rules/no-props-spread.md +56 -0
- package/presets/mavis/next/rules/no-type-assertion-as-import-export.md +51 -0
- package/presets/mavis/next/rules/package-manager.md +11 -0
- package/presets/mavis/next/rules/playwright-agents.md +67 -0
- package/presets/mavis/next/rules/post-change-lint.md +35 -0
- package/presets/mavis/next/rules/preset-layering.md +27 -0
- package/presets/mavis/next/rules/preset-no-cross-stack-leakage.md +90 -0
- package/presets/mavis/next/rules/preset-pr-checklist.md +35 -0
- package/presets/mavis/next/rules/preset-token-budget.md +36 -0
- package/presets/mavis/next/rules/preset-twin-sync.md +65 -0
- package/presets/mavis/next/rules/product-specs-authoring.md +112 -0
- package/presets/mavis/next/rules/product-specs.md +56 -0
- package/presets/mavis/next/rules/public-imports.md +50 -0
- package/presets/mavis/next/rules/react-a11y-coding.md +31 -0
- package/presets/mavis/next/rules/react-next-anti-hallucination.md +60 -0
- package/presets/mavis/next/rules/react-ui.md +105 -0
- package/presets/mavis/next/rules/reference-features.md +45 -0
- package/presets/mavis/next/rules/security-next.md +45 -0
- package/presets/mavis/next/rules/store-rtk.md +78 -0
- package/presets/mavis/next/rules/technical-retro.md +11 -0
- package/presets/mavis/next/rules/tests-e2e-structure.md +72 -0
- package/presets/mavis/next/rules/tests-unit.md +72 -0
- package/presets/mavis/next/rules/types-jsdoc.md +43 -0
- package/presets/mavis/next/rules/ux-design.md +99 -0
- package/presets/mavis/next/skills/README.md +21 -0
- package/presets/mavis/next/skills/ci-investigation/SKILL.md +39 -0
- package/presets/mavis/next/skills/code-review/SKILL.md +39 -0
- package/presets/mavis/next/skills/debug-investigation/SKILL.md +26 -0
- package/presets/mavis/next/skills/feature-delivery/SKILL.md +34 -0
- package/presets/mavis/next/skills/mockup-review/SKILL.md +24 -0
- package/presets/mavis/next/skills/playwright-e2e/SKILL.md +28 -0
- package/presets/mavis/next/skills/react-performance/SKILL.md +39 -0
- package/presets/mavis/next/skills/spec-authoring/SKILL.md +21 -0
- package/presets/mavis/next/skills/spec-discovery/SKILL.md +53 -0
- package/presets/mavis/next/skills/technical-retro/SKILL.md +49 -0
- package/presets/mavis/next/skills/unit-testing/SKILL.md +29 -0
- package/presets/mavis/next/skills/ux-design/SKILL.md +31 -0
- package/presets/mavis/next/skills/write-adr/SKILL.md +36 -0
- package/presets/mavis/next/team/README.md +148 -0
- package/presets/mavis/next/team/conventions.md +21 -0
- package/presets/mavis/next/team/fixtures/artifact-manifest.example.json +79 -0
- package/presets/mavis/next/team/fixtures/bugfix-standard.json +25 -0
- package/presets/mavis/next/team/fixtures/feature-full.json +29 -0
- package/presets/mavis/next/team/fixtures/feature-light.json +27 -0
- package/presets/mavis/next/team/fixtures/feature-with-figma-url.json +17 -0
- package/presets/mavis/next/team/fixtures/feature-with-ux-no-figma.json +17 -0
- package/presets/mavis/next/team/fixtures/memlog.example.md +9 -0
- package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/human-gate/metrics.json +69 -0
- package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/missing-ledger/status.json +5 -0
- package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/parallel-receipts/metrics.json +79 -0
- package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/serial-retry/metrics.json +124 -0
- package/presets/mavis/next/team/fixtures/metrics-scenarios/tasks/validation-failed/metrics.json +124 -0
- package/presets/mavis/next/team/fixtures/metrics.example.json +54 -0
- package/presets/mavis/next/team/fixtures/mockup-review-fail-embedded-status.json +8 -0
- package/presets/mavis/next/team/fixtures/mockup-review-standalone.json +14 -0
- package/presets/mavis/next/team/fixtures/ux-design-standalone.json +15 -0
- package/presets/mavis/next/team/tasks/.gitkeep +0 -0
- package/presets/mavis/platform-contract.json +131 -0
- package/scripts/capture-cli-golden.mjs +44 -0
- package/scripts/check-chain-hook-coverage.sh +1 -0
- package/scripts/check-mavis-adapter-map.mjs +294 -0
- package/scripts/check-mavis-local-overlay.mjs +56 -0
- package/scripts/check-mavis-platform-contract.mjs +388 -0
- package/scripts/check-mavis-token-budget.mjs +48 -0
- package/scripts/check-preset-leakage.sh +35 -3
- package/scripts/check-preset-structure.sh +63 -0
- package/scripts/check-shared-core-drift.sh +18 -0
- package/scripts/check-task-router-intents.sh +15 -2
- package/scripts/fixtures/cli-golden/claude/next.json +130 -0
- package/scripts/fixtures/cli-golden/cursor/next.json +132 -0
- package/scripts/fixtures/cli-golden/mavis/next.json +125 -0
- package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/cursor/AGENTS.md +1 -0
- package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/cursor/rules/extra.mdc +1 -0
- package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/cursor/rules/sample.mdc +2 -0
- package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/mavis/MAVIS.md +1 -0
- package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/mavis/adapter-map.json +26 -0
- package/scripts/fixtures/mavis-adapter-map/invalid-unmapped/mavis/rules/sample.md +2 -0
- package/scripts/fixtures/mavis-adapter-map/valid/cursor/AGENTS.md +1 -0
- package/scripts/fixtures/mavis-adapter-map/valid/cursor/rules/sample.mdc +2 -0
- package/scripts/fixtures/mavis-adapter-map/valid/mavis/MAVIS.md +1 -0
- package/scripts/fixtures/mavis-adapter-map/valid/mavis/adapter-map.json +26 -0
- package/scripts/fixtures/mavis-adapter-map/valid/mavis/rules/sample.md +2 -0
- package/scripts/fixtures/mavis-platform-contract/invalid-minimax-destination.json +131 -0
- package/scripts/fixtures/mavis-platform-contract/invalid-missing-capability.json +126 -0
- package/scripts/fixtures/mavis-platform-contract/invalid-released-unknown-stack.json +133 -0
- package/scripts/fixtures/mavis-platform-contract/invalid-unknown-native-path.json +131 -0
- package/scripts/fixtures/mavis-platform-contract/invalid-version-pin.json +132 -0
- package/scripts/fixtures/mavis-platform-contract/valid.json +131 -0
- package/scripts/fixtures/mavis-probe/AGENTS.md +6 -0
- package/scripts/fixtures/mavis-probe/agents/probe-agent.md +6 -0
- package/scripts/fixtures/mavis-probe/fake-mcode.mjs +98 -0
- package/scripts/fixtures/mavis-probe/output.schema.json +28 -0
- package/scripts/fixtures/mavis-probe/rules/probe.md +5 -0
- package/scripts/fixtures/mavis-probe/skills/probe/SKILL.md +11 -0
- package/scripts/generate-mavis-next.mjs +704 -0
- package/scripts/lib/cli-golden.mjs +50 -0
- package/scripts/lib/discover-hooks.mjs +72 -0
- package/scripts/probe-mavis-capabilities.mjs +480 -0
- package/scripts/test-agent-task-metrics-hooks.mjs +22 -16
- package/scripts/test-chain-team-phases-coverage.mjs +10 -7
- package/scripts/test-cli-init-clean.mjs +256 -0
- package/scripts/test-cli-mcp-merge.mjs +23 -0
- package/scripts/test-mavis-context-budget.mjs +55 -0
- package/scripts/test-mavis-orchestration.mjs +649 -0
- package/scripts/test-probe-mavis-capabilities.mjs +205 -0
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { execFileSync } from 'node:child_process';
|
|
2
|
+
import crypto from 'node:crypto';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
|
|
6
|
+
export function sha256File(filePath) {
|
|
7
|
+
return crypto.createHash('sha256').update(fs.readFileSync(filePath)).digest('hex');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function walkRelativeFiles(root) {
|
|
11
|
+
const files = [];
|
|
12
|
+
const visit = (dir) => {
|
|
13
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
14
|
+
const full = path.join(dir, entry.name);
|
|
15
|
+
if (entry.name === '.DS_Store') {
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if (entry.isDirectory()) {
|
|
19
|
+
visit(full);
|
|
20
|
+
} else if (entry.isFile()) {
|
|
21
|
+
files.push(path.relative(root, full).split(path.sep).join('/'));
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
visit(root);
|
|
26
|
+
return files.sort();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function snapshotInstall(root) {
|
|
30
|
+
const files = {};
|
|
31
|
+
for (const rel of walkRelativeFiles(root)) {
|
|
32
|
+
files[rel] = sha256File(path.join(root, rel));
|
|
33
|
+
}
|
|
34
|
+
return files;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function runInit(cli, cwd, tool, preset) {
|
|
38
|
+
return execFileSync(process.execPath, [cli, 'init', tool, '--preset', preset, '--cwd', cwd], {
|
|
39
|
+
encoding: 'utf8',
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export function goldenDocument({ tool, preset, files }) {
|
|
44
|
+
return {
|
|
45
|
+
schemaVersion: 1,
|
|
46
|
+
tool,
|
|
47
|
+
preset,
|
|
48
|
+
files,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import fs from 'node:fs';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
|
|
4
|
+
export function loadReleasedMavisStacks(presetsRoot) {
|
|
5
|
+
const contractPath = path.join(presetsRoot, 'mavis', 'platform-contract.json');
|
|
6
|
+
if (!fs.existsSync(contractPath)) {
|
|
7
|
+
return [];
|
|
8
|
+
}
|
|
9
|
+
const contract = JSON.parse(fs.readFileSync(contractPath, 'utf8'));
|
|
10
|
+
return Array.isArray(contract.releasedStacks) ? contract.releasedStacks : [];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function discoverChainHooks(presetsRoot) {
|
|
14
|
+
const hooks = [];
|
|
15
|
+
for (const platform of ['cursor', 'claude']) {
|
|
16
|
+
const platformDir = path.join(presetsRoot, platform);
|
|
17
|
+
if (!fs.existsSync(platformDir)) {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
for (const stack of fs.readdirSync(platformDir)) {
|
|
21
|
+
const hook = path.join(platformDir, stack, 'hooks', 'chain-team-phases.sh');
|
|
22
|
+
if (fs.existsSync(hook)) {
|
|
23
|
+
hooks.push(hook);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
for (const stack of loadReleasedMavisStacks(presetsRoot)) {
|
|
28
|
+
const hook = path.join(presetsRoot, 'mavis', stack, 'hooks', 'chain-team-phases.sh');
|
|
29
|
+
if (fs.existsSync(hook)) {
|
|
30
|
+
hooks.push(hook);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return hooks;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function platformFromHook(hookPath) {
|
|
37
|
+
const parts = hookPath.split(path.sep);
|
|
38
|
+
const presetsIndex = parts.lastIndexOf('presets');
|
|
39
|
+
if (presetsIndex >= 0 && parts[presetsIndex + 1]) {
|
|
40
|
+
return parts[presetsIndex + 1];
|
|
41
|
+
}
|
|
42
|
+
if (hookPath.includes(`${path.sep}mavis${path.sep}`)) {
|
|
43
|
+
return 'mavis';
|
|
44
|
+
}
|
|
45
|
+
if (hookPath.includes(`${path.sep}cursor${path.sep}`)) {
|
|
46
|
+
return 'cursor';
|
|
47
|
+
}
|
|
48
|
+
return 'claude';
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function expectedLegacyHookCount(presetsRoot) {
|
|
52
|
+
let count = 0;
|
|
53
|
+
for (const platform of ['cursor', 'claude']) {
|
|
54
|
+
const platformDir = path.join(presetsRoot, platform);
|
|
55
|
+
if (!fs.existsSync(platformDir)) {
|
|
56
|
+
continue;
|
|
57
|
+
}
|
|
58
|
+
for (const stack of fs.readdirSync(platformDir)) {
|
|
59
|
+
const hook = path.join(platformDir, stack, 'hooks', 'chain-team-phases.sh');
|
|
60
|
+
if (fs.existsSync(hook)) {
|
|
61
|
+
count += 1;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return count;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function expectedHookCount(presetsRoot) {
|
|
69
|
+
return expectedLegacyHookCount(presetsRoot) + loadReleasedMavisStacks(presetsRoot).filter((stack) =>
|
|
70
|
+
fs.existsSync(path.join(presetsRoot, 'mavis', stack, 'hooks', 'chain-team-phases.sh')),
|
|
71
|
+
).length;
|
|
72
|
+
}
|
|
@@ -0,0 +1,480 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { spawnSync } from 'node:child_process';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
|
|
8
|
+
const scriptDirectory = path.dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const fixtureDirectory = path.join(scriptDirectory, 'fixtures', 'mavis-probe');
|
|
10
|
+
|
|
11
|
+
const LIBRARY_INPUTS = [
|
|
12
|
+
path.join('rules', 'probe.md'),
|
|
13
|
+
path.join('agents', 'probe-agent.md'),
|
|
14
|
+
path.join('skills', 'probe', 'SKILL.md'),
|
|
15
|
+
'output.schema.json',
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
function parseArguments(argv) {
|
|
19
|
+
const values = new Map();
|
|
20
|
+
for (let index = 0; index < argv.length; index += 2) {
|
|
21
|
+
const flag = argv[index];
|
|
22
|
+
const value = argv[index + 1];
|
|
23
|
+
if (!['--mcode', '--workdir'].includes(flag) || !value) {
|
|
24
|
+
throw new Error('Usage: probe-mavis-capabilities.mjs --mcode <path> --workdir <path>');
|
|
25
|
+
}
|
|
26
|
+
values.set(flag, value);
|
|
27
|
+
}
|
|
28
|
+
if (!values.has('--mcode') || !values.has('--workdir')) {
|
|
29
|
+
throw new Error('Both --mcode and --workdir are required');
|
|
30
|
+
}
|
|
31
|
+
return {
|
|
32
|
+
mcode: path.resolve(values.get('--mcode')),
|
|
33
|
+
workdir: path.resolve(values.get('--workdir')),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function createRedactor({ mcode, workdir, isolatedHome }) {
|
|
38
|
+
const replacements = [
|
|
39
|
+
[mcode, '<MCODE>'],
|
|
40
|
+
[workdir, '<WORKDIR>'],
|
|
41
|
+
[isolatedHome, '<PROBE_HOME>'],
|
|
42
|
+
[os.homedir(), '<HOME>'],
|
|
43
|
+
]
|
|
44
|
+
.filter(([source]) => Boolean(source))
|
|
45
|
+
.sort(([left], [right]) => right.length - left.length);
|
|
46
|
+
|
|
47
|
+
return (value) => {
|
|
48
|
+
let redacted = String(value ?? '');
|
|
49
|
+
for (const [source, target] of replacements) {
|
|
50
|
+
redacted = redacted.split(source).join(target);
|
|
51
|
+
}
|
|
52
|
+
return redacted
|
|
53
|
+
.replace(/\/(?:Users|home)\/[^/\s"']+\/\.minimax/g, '<HOME>/.minimax')
|
|
54
|
+
.replace(/(Bearer\s+)[^\s"',]+/gi, '$1<REDACTED>')
|
|
55
|
+
.replace(
|
|
56
|
+
/((?:api[_-]?key|token|secret|password)\s*[=:]\s*)[^\s"',]+/gi,
|
|
57
|
+
'$1<REDACTED>',
|
|
58
|
+
)
|
|
59
|
+
.trim();
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function commandForEvidence(args, redact) {
|
|
64
|
+
return args.map((argument) => redact(argument));
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function capability({ status, command = null, exitCode = null, observation, executed = false }) {
|
|
68
|
+
return { status, command, exitCode, observation, executed };
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function loadInlineOutputSchema() {
|
|
72
|
+
return JSON.stringify(JSON.parse(fs.readFileSync(path.join(fixtureDirectory, 'output.schema.json'), 'utf8')));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function createCapabilities(redact, mcode, workdir) {
|
|
76
|
+
const documentedMcpCommand = commandForEvidence([mcode, 'mcp', 'list', '--human'], redact);
|
|
77
|
+
const execSafety = ['--permission', 'off', '--timeout', '3m', '--max-steps', '16'];
|
|
78
|
+
const model = process.env.MAVIS_PROBE_MODEL;
|
|
79
|
+
if (model) execSafety.push('--model', model);
|
|
80
|
+
const outputSchema = loadInlineOutputSchema();
|
|
81
|
+
const structuredCommand = [
|
|
82
|
+
mcode,
|
|
83
|
+
'exec',
|
|
84
|
+
'--cwd',
|
|
85
|
+
workdir,
|
|
86
|
+
'--output-format',
|
|
87
|
+
'json',
|
|
88
|
+
...execSafety,
|
|
89
|
+
'Return the requested capability sentinels.',
|
|
90
|
+
];
|
|
91
|
+
if (process.env.MAVIS_PROBE_USE_SCHEMA === '1') {
|
|
92
|
+
structuredCommand.splice(structuredCommand.indexOf('json') + 1, 0, '--output-schema', outputSchema);
|
|
93
|
+
}
|
|
94
|
+
const roleCommand = [
|
|
95
|
+
mcode,
|
|
96
|
+
'exec',
|
|
97
|
+
'--cwd',
|
|
98
|
+
workdir,
|
|
99
|
+
'--file',
|
|
100
|
+
'agents/probe-agent.md',
|
|
101
|
+
'--output-format',
|
|
102
|
+
'json',
|
|
103
|
+
...execSafety,
|
|
104
|
+
'Return the requested role sentinel.',
|
|
105
|
+
];
|
|
106
|
+
if (process.env.MAVIS_PROBE_USE_SCHEMA === '1') {
|
|
107
|
+
roleCommand.splice(roleCommand.indexOf('json') + 1, 0, '--output-schema', outputSchema);
|
|
108
|
+
}
|
|
109
|
+
const structuredEvidence = commandForEvidence(structuredCommand, redact);
|
|
110
|
+
|
|
111
|
+
return {
|
|
112
|
+
cliVersion: capability({
|
|
113
|
+
status: 'unknown',
|
|
114
|
+
command: commandForEvidence([mcode, '--version'], redact),
|
|
115
|
+
observation: 'Not executed.',
|
|
116
|
+
}),
|
|
117
|
+
cliHelp: capability({
|
|
118
|
+
status: 'unknown',
|
|
119
|
+
command: commandForEvidence([mcode, '--help'], redact),
|
|
120
|
+
observation: 'Not executed.',
|
|
121
|
+
}),
|
|
122
|
+
freshInit: capability({
|
|
123
|
+
status: 'unknown',
|
|
124
|
+
command: commandForEvidence([mcode, 'init', workdir], redact),
|
|
125
|
+
observation: 'Not executed.',
|
|
126
|
+
}),
|
|
127
|
+
rootAgents: capability({
|
|
128
|
+
status: 'unknown',
|
|
129
|
+
command: structuredEvidence,
|
|
130
|
+
observation: 'Not executed.',
|
|
131
|
+
}),
|
|
132
|
+
referencedRule: capability({
|
|
133
|
+
status: 'unknown',
|
|
134
|
+
command: structuredEvidence,
|
|
135
|
+
observation: 'Not executed.',
|
|
136
|
+
}),
|
|
137
|
+
referencedSkill: capability({
|
|
138
|
+
status: 'unknown',
|
|
139
|
+
command: structuredEvidence,
|
|
140
|
+
observation: 'Not executed.',
|
|
141
|
+
}),
|
|
142
|
+
explicitAgentFile: capability({
|
|
143
|
+
status: 'unknown',
|
|
144
|
+
command: commandForEvidence(roleCommand, redact),
|
|
145
|
+
observation: 'Not executed.',
|
|
146
|
+
}),
|
|
147
|
+
structuredOutput: capability({
|
|
148
|
+
status: 'unknown',
|
|
149
|
+
command: structuredEvidence,
|
|
150
|
+
observation: 'Not executed.',
|
|
151
|
+
}),
|
|
152
|
+
nativeProjectRules: capability({
|
|
153
|
+
status: 'unknown',
|
|
154
|
+
command: structuredEvidence,
|
|
155
|
+
observation: 'Not executed.',
|
|
156
|
+
}),
|
|
157
|
+
nativeWorkspaceSkills: capability({
|
|
158
|
+
status: 'unknown',
|
|
159
|
+
command: structuredEvidence,
|
|
160
|
+
observation: 'Not executed.',
|
|
161
|
+
}),
|
|
162
|
+
nativeWorkspaceAgents: capability({
|
|
163
|
+
status: 'unknown',
|
|
164
|
+
command: structuredEvidence,
|
|
165
|
+
observation: 'Not executed.',
|
|
166
|
+
}),
|
|
167
|
+
projectMcp: capability({
|
|
168
|
+
status: 'unknown',
|
|
169
|
+
command: documentedMcpCommand,
|
|
170
|
+
observation:
|
|
171
|
+
'Documented inspection command only; not executed to avoid reading or changing user-global MCP state.',
|
|
172
|
+
}),
|
|
173
|
+
projectHooks: capability({
|
|
174
|
+
status: 'unknown',
|
|
175
|
+
command: null,
|
|
176
|
+
observation:
|
|
177
|
+
'No documented project hook path is assumed; manual chain execution remains the fallback.',
|
|
178
|
+
}),
|
|
179
|
+
slashCommands: capability({
|
|
180
|
+
status: 'unknown',
|
|
181
|
+
command: null,
|
|
182
|
+
observation:
|
|
183
|
+
'No file-defined slash command API is assumed; command files remain explicit procedures.',
|
|
184
|
+
}),
|
|
185
|
+
pluginSkillMcp: capability({
|
|
186
|
+
status: 'confirmed',
|
|
187
|
+
command: null,
|
|
188
|
+
observation:
|
|
189
|
+
'Plugin Skill (`skills/**/SKILL.md`) and plugin MCP (`*.mcp.json`) formats are confirmed from official MiniMax documentation; local plugin installation was not executed by this probe.',
|
|
190
|
+
}),
|
|
191
|
+
nativeTeam: capability({
|
|
192
|
+
status: 'partial',
|
|
193
|
+
command: null,
|
|
194
|
+
observation:
|
|
195
|
+
'Official Team documentation describes Leader, Worker, and Verifier; programmatic bridge controls were not executed and remain unverified.',
|
|
196
|
+
}),
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function restoreSpawnArgs(command, workdir) {
|
|
201
|
+
return command.slice(1).map((argument) => (argument === '<WORKDIR>' ? workdir : argument));
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
function runMcode(mcode, args, workdir, redact, isolatedHome) {
|
|
205
|
+
const result = spawnSync(mcode, args, {
|
|
206
|
+
cwd: workdir,
|
|
207
|
+
encoding: 'utf8',
|
|
208
|
+
env: {
|
|
209
|
+
...process.env,
|
|
210
|
+
HOME: isolatedHome,
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
const exitCode = Number.isInteger(result.status) ? result.status : null;
|
|
214
|
+
let observation = `${result.stdout ?? ''}${result.stderr ?? ''}`.trim();
|
|
215
|
+
if (result.error?.code === 'ENOENT') {
|
|
216
|
+
observation = 'Executable not found.';
|
|
217
|
+
} else if (result.error) {
|
|
218
|
+
observation = result.error.message;
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
exitCode,
|
|
222
|
+
observation: redact(observation || `Exited with code ${exitCode}.`),
|
|
223
|
+
stdout: result.stdout ?? '',
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
function runInit(mcode, workdir, redact, isolatedHome) {
|
|
228
|
+
return runMcode(mcode, ['init', workdir], workdir, redact, isolatedHome);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
const AUTH_SEED_ENTRIES = ['cli-auth', 'local-runtime.auth.json', 'config.yaml'];
|
|
232
|
+
|
|
233
|
+
function seedIsolatedAuth(operatorHome, isolatedHome) {
|
|
234
|
+
const sourceRoot = path.join(operatorHome, '.minimax');
|
|
235
|
+
const destinationRoot = path.join(isolatedHome, '.minimax');
|
|
236
|
+
if (!fs.existsSync(sourceRoot)) return { seeded: false, entries: [] };
|
|
237
|
+
const seeded = [];
|
|
238
|
+
for (const entry of AUTH_SEED_ENTRIES) {
|
|
239
|
+
const source = path.join(sourceRoot, entry);
|
|
240
|
+
if (!fs.existsSync(source)) continue;
|
|
241
|
+
const destination = path.join(destinationRoot, entry);
|
|
242
|
+
fs.cpSync(source, destination, { recursive: true });
|
|
243
|
+
seeded.push(entry);
|
|
244
|
+
}
|
|
245
|
+
return { seeded: seeded.length > 0, entries: seeded };
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function copyProbeInputs(workdir, relativeInputs) {
|
|
249
|
+
for (const relativeInput of relativeInputs) {
|
|
250
|
+
const source = path.join(fixtureDirectory, relativeInput);
|
|
251
|
+
const destination = path.join(workdir, relativeInput);
|
|
252
|
+
fs.mkdirSync(path.dirname(destination), { recursive: true });
|
|
253
|
+
fs.copyFileSync(source, destination);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function extractSentinels(value) {
|
|
258
|
+
const text = typeof value === 'string' ? value : JSON.stringify(value ?? '');
|
|
259
|
+
return [...new Set(text.match(/MAVIS_[A-Z_]+_SENTINEL/g) ?? [])];
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
function parseStructuredOutput(stdout) {
|
|
263
|
+
const parsed = JSON.parse(stdout);
|
|
264
|
+
if (parsed?.status === 'ok' && Array.isArray(parsed.sentinels)) {
|
|
265
|
+
return parsed;
|
|
266
|
+
}
|
|
267
|
+
if (parsed?.type === 'exec.result') {
|
|
268
|
+
const sentinels = extractSentinels(parsed.output);
|
|
269
|
+
if (parsed.status === 'succeeded' || sentinels.length > 0) {
|
|
270
|
+
return {
|
|
271
|
+
status: 'ok',
|
|
272
|
+
sentinels,
|
|
273
|
+
observation: `mcode wrapper status ${parsed.status}`,
|
|
274
|
+
};
|
|
275
|
+
}
|
|
276
|
+
throw new Error(`exec.result status ${parsed.status}`);
|
|
277
|
+
}
|
|
278
|
+
throw new Error('Structured output did not match a known probe or mcode wrapper shape');
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function updateExecutionCapability(target, result, status, observation) {
|
|
282
|
+
target.status = status;
|
|
283
|
+
target.exitCode = result.exitCode;
|
|
284
|
+
target.observation = observation;
|
|
285
|
+
target.executed = true;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
function writeEvidence(evidence, exitCode) {
|
|
289
|
+
process.stdout.write(`${JSON.stringify(evidence, null, 2)}\n`);
|
|
290
|
+
process.exitCode = exitCode;
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
function sentinelSet(parsed) {
|
|
294
|
+
return new Set(parsed?.sentinels ?? []);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
let options;
|
|
298
|
+
try {
|
|
299
|
+
options = parseArguments(process.argv.slice(2));
|
|
300
|
+
} catch (error) {
|
|
301
|
+
process.stdout.write(
|
|
302
|
+
`${JSON.stringify({ schemaVersion: 1, probeStatus: 'blocked', error: error.message }, null, 2)}\n`,
|
|
303
|
+
);
|
|
304
|
+
process.exitCode = 2;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
if (options) {
|
|
308
|
+
const { mcode, workdir } = options;
|
|
309
|
+
let isolatedHome;
|
|
310
|
+
try {
|
|
311
|
+
isolatedHome = fs.mkdtempSync(path.join(os.tmpdir(), 'mavis-probe-home-'));
|
|
312
|
+
const operatorHome = process.env.HOME || os.homedir();
|
|
313
|
+
const authSeed = seedIsolatedAuth(operatorHome, isolatedHome);
|
|
314
|
+
const redact = createRedactor({ mcode, workdir, isolatedHome });
|
|
315
|
+
const capabilities = createCapabilities(redact, mcode, workdir);
|
|
316
|
+
const evidence = {
|
|
317
|
+
schemaVersion: 1,
|
|
318
|
+
probeStatus: 'completed',
|
|
319
|
+
cli: {
|
|
320
|
+
executable: '<MCODE>',
|
|
321
|
+
version: null,
|
|
322
|
+
},
|
|
323
|
+
os: {
|
|
324
|
+
platform: os.platform(),
|
|
325
|
+
release: os.release(),
|
|
326
|
+
arch: os.arch(),
|
|
327
|
+
},
|
|
328
|
+
workdir: '<WORKDIR>',
|
|
329
|
+
authSeed: {
|
|
330
|
+
seeded: authSeed.seeded,
|
|
331
|
+
entries: authSeed.entries,
|
|
332
|
+
},
|
|
333
|
+
capabilities,
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
fs.mkdirSync(workdir, { recursive: true });
|
|
337
|
+
if (fs.readdirSync(workdir).length > 0) {
|
|
338
|
+
evidence.probeStatus = 'blocked';
|
|
339
|
+
capabilities.freshInit.observation = 'Workdir must be empty before the probe starts.';
|
|
340
|
+
writeEvidence(evidence, 2);
|
|
341
|
+
} else {
|
|
342
|
+
const version = runMcode(mcode, ['--version'], workdir, redact, isolatedHome);
|
|
343
|
+
const versionText = redact(version.stdout).split(/\r?\n/, 1)[0] || null;
|
|
344
|
+
updateExecutionCapability(
|
|
345
|
+
capabilities.cliVersion,
|
|
346
|
+
version,
|
|
347
|
+
version.exitCode === 0 && versionText ? 'confirmed' : 'unknown',
|
|
348
|
+
version.exitCode === 0 && versionText ? versionText : version.observation,
|
|
349
|
+
);
|
|
350
|
+
|
|
351
|
+
if (capabilities.cliVersion.status !== 'confirmed') {
|
|
352
|
+
evidence.probeStatus = 'blocked';
|
|
353
|
+
writeEvidence(evidence, 2);
|
|
354
|
+
} else {
|
|
355
|
+
evidence.cli.version = versionText;
|
|
356
|
+
|
|
357
|
+
const help = runMcode(mcode, ['--help'], workdir, redact, isolatedHome);
|
|
358
|
+
updateExecutionCapability(
|
|
359
|
+
capabilities.cliHelp,
|
|
360
|
+
help,
|
|
361
|
+
help.exitCode === 0 ? 'confirmed' : 'unknown',
|
|
362
|
+
help.observation,
|
|
363
|
+
);
|
|
364
|
+
|
|
365
|
+
const init = runInit(mcode, workdir, redact, isolatedHome);
|
|
366
|
+
updateExecutionCapability(
|
|
367
|
+
capabilities.freshInit,
|
|
368
|
+
init,
|
|
369
|
+
init.exitCode === 0 ? 'confirmed' : 'unknown',
|
|
370
|
+
init.observation,
|
|
371
|
+
);
|
|
372
|
+
|
|
373
|
+
copyProbeInputs(workdir, LIBRARY_INPUTS);
|
|
374
|
+
|
|
375
|
+
const nativeArgs = restoreSpawnArgs(capabilities.nativeProjectRules.command, workdir);
|
|
376
|
+
const nativeResult = runMcode(mcode, nativeArgs, workdir, redact, isolatedHome);
|
|
377
|
+
let nativeOutput = null;
|
|
378
|
+
try {
|
|
379
|
+
nativeOutput = nativeResult.exitCode === 0 ? parseStructuredOutput(nativeResult.stdout) : null;
|
|
380
|
+
} catch (error) {
|
|
381
|
+
nativeResult.observation = redact(error.message);
|
|
382
|
+
}
|
|
383
|
+
const nativeSentinels = sentinelSet(nativeOutput);
|
|
384
|
+
const nativeObservation = redact(nativeOutput?.observation ?? nativeResult.observation);
|
|
385
|
+
updateExecutionCapability(
|
|
386
|
+
capabilities.nativeProjectRules,
|
|
387
|
+
nativeResult,
|
|
388
|
+
nativeSentinels.has('MAVIS_RULE_SENTINEL') ? 'confirmed' : 'unknown',
|
|
389
|
+
nativeSentinels.has('MAVIS_RULE_SENTINEL')
|
|
390
|
+
? 'Rule sentinel returned without an explicit root AGENTS.md reference.'
|
|
391
|
+
: nativeObservation,
|
|
392
|
+
);
|
|
393
|
+
updateExecutionCapability(
|
|
394
|
+
capabilities.nativeWorkspaceSkills,
|
|
395
|
+
nativeResult,
|
|
396
|
+
nativeSentinels.has('MAVIS_SKILL_SENTINEL') ? 'confirmed' : 'unknown',
|
|
397
|
+
nativeSentinels.has('MAVIS_SKILL_SENTINEL')
|
|
398
|
+
? 'Skill sentinel returned without an explicit root AGENTS.md reference.'
|
|
399
|
+
: nativeObservation,
|
|
400
|
+
);
|
|
401
|
+
updateExecutionCapability(
|
|
402
|
+
capabilities.nativeWorkspaceAgents,
|
|
403
|
+
nativeResult,
|
|
404
|
+
nativeSentinels.has('MAVIS_AGENT_FILE_SENTINEL') ? 'confirmed' : 'unknown',
|
|
405
|
+
nativeSentinels.has('MAVIS_AGENT_FILE_SENTINEL')
|
|
406
|
+
? 'Agent sentinel returned without mcode exec --file.'
|
|
407
|
+
: nativeObservation,
|
|
408
|
+
);
|
|
409
|
+
|
|
410
|
+
copyProbeInputs(workdir, ['AGENTS.md']);
|
|
411
|
+
|
|
412
|
+
const rootArgs = restoreSpawnArgs(capabilities.rootAgents.command, workdir);
|
|
413
|
+
const rootResult = runMcode(mcode, rootArgs, workdir, redact, isolatedHome);
|
|
414
|
+
let rootOutput = null;
|
|
415
|
+
try {
|
|
416
|
+
rootOutput = rootResult.exitCode === 0 ? parseStructuredOutput(rootResult.stdout) : null;
|
|
417
|
+
} catch (error) {
|
|
418
|
+
rootResult.observation = redact(error.message);
|
|
419
|
+
}
|
|
420
|
+
const rootSentinels = sentinelSet(rootOutput);
|
|
421
|
+
updateExecutionCapability(
|
|
422
|
+
capabilities.rootAgents,
|
|
423
|
+
rootResult,
|
|
424
|
+
rootSentinels.has('MAVIS_AGENTS_SENTINEL') ? 'confirmed' : 'unknown',
|
|
425
|
+
redact(rootOutput?.observation ?? rootResult.observation),
|
|
426
|
+
);
|
|
427
|
+
updateExecutionCapability(
|
|
428
|
+
capabilities.referencedRule,
|
|
429
|
+
rootResult,
|
|
430
|
+
rootSentinels.has('MAVIS_RULE_SENTINEL') ? 'confirmed' : 'unknown',
|
|
431
|
+
rootSentinels.has('MAVIS_RULE_SENTINEL')
|
|
432
|
+
? 'Rule sentinel returned through the explicit root AGENTS.md reference.'
|
|
433
|
+
: rootResult.observation,
|
|
434
|
+
);
|
|
435
|
+
updateExecutionCapability(
|
|
436
|
+
capabilities.referencedSkill,
|
|
437
|
+
rootResult,
|
|
438
|
+
rootSentinels.has('MAVIS_SKILL_SENTINEL') ? 'confirmed' : 'unknown',
|
|
439
|
+
rootSentinels.has('MAVIS_SKILL_SENTINEL')
|
|
440
|
+
? 'Skill sentinel returned through the explicit root AGENTS.md reference.'
|
|
441
|
+
: rootResult.observation,
|
|
442
|
+
);
|
|
443
|
+
updateExecutionCapability(
|
|
444
|
+
capabilities.structuredOutput,
|
|
445
|
+
rootResult,
|
|
446
|
+
rootOutput ? 'confirmed' : 'unknown',
|
|
447
|
+
rootOutput
|
|
448
|
+
? 'Output parsed as JSON and matched the required probe fields.'
|
|
449
|
+
: rootResult.observation,
|
|
450
|
+
);
|
|
451
|
+
|
|
452
|
+
const roleArgs = restoreSpawnArgs(capabilities.explicitAgentFile.command, workdir);
|
|
453
|
+
const roleResult = runMcode(mcode, roleArgs, workdir, redact, isolatedHome);
|
|
454
|
+
let roleOutput = null;
|
|
455
|
+
try {
|
|
456
|
+
roleOutput = roleResult.exitCode === 0 ? parseStructuredOutput(roleResult.stdout) : null;
|
|
457
|
+
} catch (error) {
|
|
458
|
+
roleResult.observation = redact(error.message);
|
|
459
|
+
}
|
|
460
|
+
updateExecutionCapability(
|
|
461
|
+
capabilities.explicitAgentFile,
|
|
462
|
+
roleResult,
|
|
463
|
+
roleOutput?.sentinels.includes('MAVIS_AGENT_FILE_SENTINEL') ? 'confirmed' : 'unknown',
|
|
464
|
+
redact(roleOutput?.observation ?? roleResult.observation),
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
const hardNoGoObserved =
|
|
468
|
+
capabilities.rootAgents.status !== 'confirmed' ||
|
|
469
|
+
capabilities.explicitAgentFile.status !== 'confirmed' ||
|
|
470
|
+
capabilities.structuredOutput.status !== 'confirmed';
|
|
471
|
+
if (hardNoGoObserved) evidence.probeStatus = 'blocked';
|
|
472
|
+
writeEvidence(evidence, hardNoGoObserved ? 2 : 0);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
} finally {
|
|
476
|
+
if (isolatedHome) {
|
|
477
|
+
fs.rmSync(isolatedHome, { recursive: true, force: true });
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
}
|