zilmate 1.9.9 → 1.10.2
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/.agents/skills/ad-creative/SKILL.md +362 -0
- package/.agents/skills/ad-creative/evals/evals.json +90 -0
- package/.agents/skills/ad-creative/references/generative-tools.md +637 -0
- package/.agents/skills/ad-creative/references/platform-specs.md +213 -0
- package/.agents/skills/ai-seo/SKILL.md +489 -0
- package/.agents/skills/ai-seo/evals/evals.json +90 -0
- package/.agents/skills/ai-seo/references/content-patterns.md +285 -0
- package/.agents/skills/ai-seo/references/content-types.md +71 -0
- package/.agents/skills/ai-seo/references/okf.md +104 -0
- package/.agents/skills/ai-seo/references/platform-ranking-factors.md +154 -0
- package/.agents/skills/clerk-backend-api/SKILL.md +426 -0
- package/.agents/skills/clerk-backend-api/evals/evals.json +87 -0
- package/.agents/skills/clerk-backend-api/scripts/api-specs-context.sh +30 -0
- package/.agents/skills/clerk-backend-api/scripts/execute-request.sh +88 -0
- package/.agents/skills/clerk-backend-api/scripts/extract-endpoint-detail.sh +165 -0
- package/.agents/skills/clerk-backend-api/scripts/extract-tag-endpoints.sh +208 -0
- package/.agents/skills/clerk-backend-api/scripts/extract-tags.js +14 -0
- package/.agents/skills/copy-editing/SKILL.md +457 -0
- package/.agents/skills/copy-editing/evals/evals.json +89 -0
- package/.agents/skills/copy-editing/references/checklist.md +66 -0
- package/.agents/skills/copy-editing/references/content-refresh.md +38 -0
- package/.agents/skills/copy-editing/references/plain-english-alternatives.md +394 -0
- package/.agents/skills/hyperframes/SKILL.md +163 -0
- package/.agents/skills/hyperframes-cli/SKILL.md +109 -0
- package/.agents/skills/hyperframes-cli/references/doctor-browser.md +45 -0
- package/.agents/skills/hyperframes-cli/references/init-and-scaffold.md +51 -0
- package/.agents/skills/hyperframes-cli/references/lambda.md +132 -0
- package/.agents/skills/hyperframes-cli/references/lint-validate-inspect.md +121 -0
- package/.agents/skills/hyperframes-cli/references/preview-render.md +109 -0
- package/.agents/skills/hyperframes-cli/references/upgrade-info-misc.md +75 -0
- package/.agents/skills/hyperframes-media/SKILL.md +97 -0
- package/.agents/skills/hyperframes-media/assets/sfx/CREDITS.md +35 -0
- package/.agents/skills/hyperframes-media/assets/sfx/manifest.json +97 -0
- package/.agents/skills/hyperframes-media/references/bgm.md +72 -0
- package/.agents/skills/hyperframes-media/references/captions/authoring.md +159 -0
- package/.agents/skills/hyperframes-media/references/captions/motion.md +87 -0
- package/.agents/skills/hyperframes-media/references/captions/transcript-handling.md +97 -0
- package/.agents/skills/hyperframes-media/references/remove-background.md +143 -0
- package/.agents/skills/hyperframes-media/references/requirements.md +29 -0
- package/.agents/skills/hyperframes-media/references/sfx.md +42 -0
- package/.agents/skills/hyperframes-media/references/transcribe.md +52 -0
- package/.agents/skills/hyperframes-media/references/tts-to-captions.md +24 -0
- package/.agents/skills/hyperframes-media/references/tts.md +135 -0
- package/.agents/skills/hyperframes-media/scripts/audio.mjs +282 -0
- package/.agents/skills/hyperframes-media/scripts/heygen-tts.mjs +121 -0
- package/.agents/skills/hyperframes-media/scripts/lib/bgm.mjs +235 -0
- package/.agents/skills/hyperframes-media/scripts/lib/heygen.mjs +131 -0
- package/.agents/skills/hyperframes-media/scripts/lib/sfx.mjs +128 -0
- package/.agents/skills/hyperframes-media/scripts/lib/tts.mjs +220 -0
- package/.agents/skills/hyperframes-media/scripts/lyria-recipe.py +128 -0
- package/.agents/skills/hyperframes-media/scripts/wait-bgm.mjs +167 -0
- package/.agents/skills/hyperframes-registry/SKILL.md +101 -0
- package/.agents/skills/hyperframes-registry/examples/add-block.md +51 -0
- package/.agents/skills/hyperframes-registry/examples/add-component.md +73 -0
- package/.agents/skills/hyperframes-registry/references/contributing.md +166 -0
- package/.agents/skills/hyperframes-registry/references/demo-html-pattern.md +54 -0
- package/.agents/skills/hyperframes-registry/references/discovery.md +215 -0
- package/.agents/skills/hyperframes-registry/references/install-locations.md +45 -0
- package/.agents/skills/hyperframes-registry/references/templates.md +417 -0
- package/.agents/skills/hyperframes-registry/references/wiring-blocks.md +61 -0
- package/.agents/skills/hyperframes-registry/references/wiring-components.md +39 -0
- package/.agents/skills/marketing-psychology/SKILL.md +455 -0
- package/.agents/skills/marketing-psychology/evals/evals.json +88 -0
- package/.agents/skills/mintlify/SKILL.md +328 -0
- package/.agents/skills/product-launch-video/SKILL.md +206 -0
- package/.agents/skills/product-launch-video/references/cut-catalog.md +220 -0
- package/.agents/skills/product-launch-video/references/motion-language.md +156 -0
- package/.agents/skills/product-launch-video/references/story-design.md +373 -0
- package/.agents/skills/product-launch-video/references/visual-design.md +126 -0
- package/.agents/skills/product-launch-video/scripts/assemble-index.mjs +570 -0
- package/.agents/skills/product-launch-video/scripts/audio.mjs +253 -0
- package/.agents/skills/product-launch-video/scripts/build-frame.mjs +536 -0
- package/.agents/skills/product-launch-video/scripts/captions.mjs +508 -0
- package/.agents/skills/product-launch-video/scripts/lib/assets.mjs +55 -0
- package/.agents/skills/product-launch-video/scripts/lib/dimensions.mjs +45 -0
- package/.agents/skills/product-launch-video/scripts/lib/storyboard.mjs +249 -0
- package/.agents/skills/product-launch-video/scripts/lib/tokens.mjs +204 -0
- package/.agents/skills/product-launch-video/scripts/lib/transition-registry.mjs +38 -0
- package/.agents/skills/product-launch-video/scripts/lib/transitions.json +71 -0
- package/.agents/skills/product-launch-video/scripts/stage-assets.mjs +39 -0
- package/.agents/skills/product-launch-video/scripts/transitions.mjs +320 -0
- package/.agents/skills/product-launch-video/sub-agents/frame-worker.md +74 -0
- package/.agents/skills/prompt-engineering-patterns/SKILL.md +144 -0
- package/.agents/skills/prompt-engineering-patterns/assets/few-shot-examples.json +106 -0
- package/.agents/skills/prompt-engineering-patterns/assets/prompt-template-library.md +264 -0
- package/.agents/skills/prompt-engineering-patterns/references/chain-of-thought.md +412 -0
- package/.agents/skills/prompt-engineering-patterns/references/details.md +338 -0
- package/.agents/skills/prompt-engineering-patterns/references/few-shot-learning.md +386 -0
- package/.agents/skills/prompt-engineering-patterns/references/prompt-optimization.md +428 -0
- package/.agents/skills/prompt-engineering-patterns/references/prompt-templates.md +484 -0
- package/.agents/skills/prompt-engineering-patterns/references/system-prompts.md +195 -0
- package/.agents/skills/prompt-engineering-patterns/scripts/optimize-prompt.py +279 -0
- package/.agents/skills/remotion-to-hyperframes/SKILL.md +127 -0
- package/.agents/skills/remotion-to-hyperframes/assets/.gitkeep +0 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/run.sh +249 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/README.md +41 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/expected.json +26 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/hf-src/index.html +61 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/remotion-src/package.json +14 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/remotion-src/remotion.config.ts +13 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/remotion-src/src/Root.tsx +13 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/remotion-src/src/TitleCard.tsx +34 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/remotion-src/src/index.ts +4 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-1-title-card/remotion-src/tsconfig.json +15 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/README.md +54 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/expected.json +29 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/hf-src/index.html +118 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/remotion-src/package.json +14 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/remotion-src/remotion.config.ts +13 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/remotion-src/src/MultiScene.tsx +105 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/remotion-src/src/Root.tsx +13 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/remotion-src/src/index.ts +4 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/remotion-src/tsconfig.json +15 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-2-multi-scene/setup.sh +34 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/README.md +85 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/expected.json +41 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/hf-src/index.html +269 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/package.json +15 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/remotion.config.ts +13 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/src/Root.tsx +27 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/src/Stargazed.tsx +37 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/src/components/AnimatedNumber.tsx +23 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/src/components/StatCard.tsx +59 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/src/components/UnderlinedText.tsx +47 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/src/index.ts +4 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/src/scenes/OutroScene.tsx +18 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/src/scenes/StatsScene.tsx +34 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/src/scenes/TitleScene.tsx +55 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-3-data-driven/remotion-src/tsconfig.json +15 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/README.md +51 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/cases/01-use-state.tsx +29 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/cases/02-use-effect-deps.tsx +29 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/cases/03-async-metadata.tsx +39 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/cases/04-third-party-react.tsx +30 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/cases/05-lambda-config.tsx +38 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/cases/06-warnings-only.tsx +36 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/cases/07-custom-hook.tsx +28 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/cases/08-mixed.tsx +41 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/expected.json +85 -0
- package/.agents/skills/remotion-to-hyperframes/assets/test-corpus/tier-4-escape-hatch/validate.sh +110 -0
- package/.agents/skills/remotion-to-hyperframes/references/api-map.md +142 -0
- package/.agents/skills/remotion-to-hyperframes/references/escape-hatch.md +115 -0
- package/.agents/skills/remotion-to-hyperframes/references/eval.md +140 -0
- package/.agents/skills/remotion-to-hyperframes/references/fonts.md +112 -0
- package/.agents/skills/remotion-to-hyperframes/references/limitations.md +136 -0
- package/.agents/skills/remotion-to-hyperframes/references/lottie.md +121 -0
- package/.agents/skills/remotion-to-hyperframes/references/media.md +149 -0
- package/.agents/skills/remotion-to-hyperframes/references/parameters.md +167 -0
- package/.agents/skills/remotion-to-hyperframes/references/sequencing.md +195 -0
- package/.agents/skills/remotion-to-hyperframes/references/timing.md +165 -0
- package/.agents/skills/remotion-to-hyperframes/references/transitions.md +114 -0
- package/.agents/skills/remotion-to-hyperframes/scripts/.gitkeep +0 -0
- package/.agents/skills/remotion-to-hyperframes/scripts/frame_strip.sh +107 -0
- package/.agents/skills/remotion-to-hyperframes/scripts/lint_source.py +358 -0
- package/.agents/skills/remotion-to-hyperframes/scripts/render_diff.sh +103 -0
- package/.agents/skills/remotion-to-hyperframes/scripts/tests/fixtures/blocker.tsx +50 -0
- package/.agents/skills/remotion-to-hyperframes/scripts/tests/fixtures/clean.tsx +46 -0
- package/.agents/skills/remotion-to-hyperframes/scripts/tests/smoke.sh +90 -0
- package/.agents/skills/seo-audit/SKILL.md +497 -0
- package/.agents/skills/seo-audit/evals/evals.json +136 -0
- package/.agents/skills/seo-audit/references/ai-writing-detection.md +200 -0
- package/.agents/skills/seo-audit/references/international-seo.md +230 -0
- package/README.md +4 -2
- package/SDK.md +64 -1
- package/dist/agents/coding.agent.d.ts +558 -0
- package/dist/agents/coding.agent.d.ts.map +1 -1
- package/dist/agents/coding.agent.js +8 -0
- package/dist/agents/coding.agent.js.map +1 -1
- package/dist/agents/developer-helper.agent.d.ts +712 -0
- package/dist/agents/developer-helper.agent.d.ts.map +1 -1
- package/dist/agents/developer-helper.agent.js +6 -0
- package/dist/agents/developer-helper.agent.js.map +1 -1
- package/dist/agents/docs-research.agent.d.ts +8 -0
- package/dist/agents/docs-research.agent.d.ts.map +1 -1
- package/dist/agents/finance.agent.d.ts +8 -0
- package/dist/agents/finance.agent.d.ts.map +1 -1
- package/dist/agents/manager.d.ts +837 -2
- package/dist/agents/manager.d.ts.map +1 -1
- package/dist/agents/manager.js +28 -0
- package/dist/agents/manager.js.map +1 -1
- package/dist/agents/security.agent.d.ts +165 -3
- package/dist/agents/security.agent.d.ts.map +1 -1
- package/dist/agents/security.agent.js +3 -0
- package/dist/agents/security.agent.js.map +1 -1
- package/dist/agents/swarm/main.js +1 -1
- package/dist/agents/swarm/main.js.map +1 -1
- package/dist/agents/swarm/registry.d.ts.map +1 -1
- package/dist/agents/swarm/registry.js +232 -26
- package/dist/agents/swarm/registry.js.map +1 -1
- package/dist/cli/doctor.d.ts +14 -0
- package/dist/cli/doctor.d.ts.map +1 -1
- package/dist/cli/doctor.js +91 -0
- package/dist/cli/doctor.js.map +1 -1
- package/dist/cli/menu.d.ts.map +1 -1
- package/dist/cli/menu.js +102 -0
- package/dist/cli/menu.js.map +1 -1
- package/dist/cli/setup.d.ts +10 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +178 -0
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/swarm.d.ts +1 -0
- package/dist/cli/swarm.d.ts.map +1 -1
- package/dist/cli/swarm.js +47 -8
- package/dist/cli/swarm.js.map +1 -1
- package/dist/cli/theme.d.ts +0 -24
- package/dist/cli/theme.d.ts.map +1 -1
- package/dist/cli/theme.js +6 -2
- package/dist/cli/theme.js.map +1 -1
- package/dist/config/env.d.ts +10 -0
- package/dist/config/env.d.ts.map +1 -1
- package/dist/config/env.js +38 -17
- package/dist/config/env.js.map +1 -1
- package/dist/index.js +96 -5
- package/dist/index.js.map +1 -1
- package/dist/jobs/trigger-orchestrator.d.ts +5 -1
- package/dist/jobs/trigger-orchestrator.d.ts.map +1 -1
- package/dist/jobs/trigger-orchestrator.js +29 -9
- package/dist/jobs/trigger-orchestrator.js.map +1 -1
- package/dist/jobs/trigger-router.d.ts.map +1 -1
- package/dist/jobs/trigger-router.js +3 -2
- package/dist/jobs/trigger-router.js.map +1 -1
- package/dist/memory/corporate-wiki.d.ts +15 -0
- package/dist/memory/corporate-wiki.d.ts.map +1 -0
- package/dist/memory/corporate-wiki.js +152 -0
- package/dist/memory/corporate-wiki.js.map +1 -0
- package/dist/memory/scratchpad.d.ts +2 -0
- package/dist/memory/scratchpad.d.ts.map +1 -1
- package/dist/memory/scratchpad.js +27 -0
- package/dist/memory/scratchpad.js.map +1 -1
- package/dist/observability/doctor.d.ts.map +1 -1
- package/dist/observability/doctor.js +12 -4
- package/dist/observability/doctor.js.map +1 -1
- package/dist/observability/traces.d.ts +72 -0
- package/dist/observability/traces.d.ts.map +1 -0
- package/dist/observability/traces.js +1134 -0
- package/dist/observability/traces.js.map +1 -0
- package/dist/runtime/swarm.d.ts +1 -1
- package/dist/runtime/swarm.d.ts.map +1 -1
- package/dist/runtime/swarm.js +54 -25
- package/dist/runtime/swarm.js.map +1 -1
- package/dist/safety/approvals.d.ts +2 -2
- package/dist/safety/approvals.d.ts.map +1 -1
- package/dist/safety/approvals.js +47 -1
- package/dist/safety/approvals.js.map +1 -1
- package/dist/safety/redaction.d.ts.map +1 -1
- package/dist/safety/redaction.js +10 -0
- package/dist/safety/redaction.js.map +1 -1
- package/dist/tools/cloud.tool.d.ts +394 -0
- package/dist/tools/cloud.tool.d.ts.map +1 -0
- package/dist/tools/cloud.tool.js +784 -0
- package/dist/tools/cloud.tool.js.map +1 -0
- package/dist/tools/computer-use.tool.d.ts +2 -2
- package/dist/tools/corporate-wiki.tool.d.ts +22 -0
- package/dist/tools/corporate-wiki.tool.d.ts.map +1 -0
- package/dist/tools/corporate-wiki.tool.js +43 -0
- package/dist/tools/corporate-wiki.tool.js.map +1 -0
- package/dist/tools/devops.tool.d.ts +162 -0
- package/dist/tools/devops.tool.d.ts.map +1 -0
- package/dist/tools/devops.tool.js +377 -0
- package/dist/tools/devops.tool.js.map +1 -0
- package/dist/tools/multimedia.tool.d.ts +126 -0
- package/dist/tools/multimedia.tool.d.ts.map +1 -0
- package/dist/tools/multimedia.tool.js +533 -0
- package/dist/tools/multimedia.tool.js.map +1 -0
- package/dist/tools/osint.tool.d.ts +6 -6
- package/dist/tools/sandbox-dev.tool.d.ts +15 -0
- package/dist/tools/sandbox-dev.tool.d.ts.map +1 -0
- package/dist/tools/sandbox-dev.tool.js +146 -0
- package/dist/tools/sandbox-dev.tool.js.map +1 -0
- package/dist/tools/scratchpad.tool.d.ts +8 -0
- package/dist/tools/scratchpad.tool.d.ts.map +1 -1
- package/dist/tools/scratchpad.tool.js +40 -1
- package/dist/tools/scratchpad.tool.js.map +1 -1
- package/dist/tools/setup-assistant.tool.d.ts +1 -1
- package/dist/tools/swarm-ops.tool.d.ts +14 -0
- package/dist/tools/swarm-ops.tool.d.ts.map +1 -1
- package/dist/tools/swarm-ops.tool.js +47 -0
- package/dist/tools/swarm-ops.tool.js.map +1 -1
- package/dist/tools/sysops.tool.d.ts +157 -0
- package/dist/tools/sysops.tool.d.ts.map +1 -0
- package/dist/tools/sysops.tool.js +643 -0
- package/dist/tools/sysops.tool.js.map +1 -0
- package/dist/voice/deepgram.d.ts.map +1 -1
- package/dist/voice/deepgram.js +30 -2
- package/dist/voice/deepgram.js.map +1 -1
- package/package.json +8 -1
- package/scripts/release-github.mjs +23 -16
|
@@ -0,0 +1,643 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { promisify } from 'node:util';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import os from 'node:os';
|
|
6
|
+
import { tool } from 'ai';
|
|
7
|
+
import { z } from 'zod';
|
|
8
|
+
import { emitProgress } from '../runtime/progress.js';
|
|
9
|
+
import { resolveWorkspaceRoot } from '../workspace/paths.js';
|
|
10
|
+
const execFileAsync = promisify(execFile);
|
|
11
|
+
async function commandExists(command) {
|
|
12
|
+
const probe = process.platform === 'win32' ? 'where.exe' : 'which';
|
|
13
|
+
try {
|
|
14
|
+
await execFileAsync(probe, [command], { windowsHide: true, timeout: 5000 });
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function getCpuTicks() {
|
|
22
|
+
const cpus = os.cpus();
|
|
23
|
+
let user = 0;
|
|
24
|
+
let nice = 0;
|
|
25
|
+
let sys = 0;
|
|
26
|
+
let idle = 0;
|
|
27
|
+
let irq = 0;
|
|
28
|
+
for (const cpu of cpus) {
|
|
29
|
+
user += cpu.times.user;
|
|
30
|
+
nice += cpu.times.nice;
|
|
31
|
+
sys += cpu.times.sys;
|
|
32
|
+
idle += cpu.times.idle;
|
|
33
|
+
irq += cpu.times.irq;
|
|
34
|
+
}
|
|
35
|
+
const total = user + nice + sys + idle + irq;
|
|
36
|
+
return { idle, total };
|
|
37
|
+
}
|
|
38
|
+
async function sampleCpuUsage() {
|
|
39
|
+
const start = getCpuTicks();
|
|
40
|
+
await new Promise(resolve => setTimeout(resolve, 150));
|
|
41
|
+
const end = getCpuTicks();
|
|
42
|
+
const idleDelta = end.idle - start.idle;
|
|
43
|
+
const totalDelta = end.total - start.total;
|
|
44
|
+
if (totalDelta === 0)
|
|
45
|
+
return 0;
|
|
46
|
+
const usage = 100 * (1 - idleDelta / totalDelta);
|
|
47
|
+
return Math.round(usage * 10) / 10;
|
|
48
|
+
}
|
|
49
|
+
async function getDiskSpace(workspaceRoot) {
|
|
50
|
+
try {
|
|
51
|
+
if (process.platform === 'win32') {
|
|
52
|
+
const driveLetter = path.parse(workspaceRoot).root.replace(':\\', '').replace(':', '') || 'C';
|
|
53
|
+
const script = `
|
|
54
|
+
Get-Volume -DriveLetter "${driveLetter}" -ErrorAction SilentlyContinue | ForEach-Object {
|
|
55
|
+
[PSCustomObject]@{
|
|
56
|
+
size = $_.Size
|
|
57
|
+
free = $_.SizeRemaining
|
|
58
|
+
}
|
|
59
|
+
} | ConvertTo-Json -Compress
|
|
60
|
+
`;
|
|
61
|
+
const { stdout } = await execFileAsync('powershell.exe', ['-NoProfile', '-Command', script], { windowsHide: true, timeout: 5000 });
|
|
62
|
+
const cleaned = stdout.trim();
|
|
63
|
+
if (cleaned) {
|
|
64
|
+
const parsed = JSON.parse(cleaned);
|
|
65
|
+
const totalGb = parsed.size / (1024 * 1024 * 1024);
|
|
66
|
+
const freeGb = parsed.free / (1024 * 1024 * 1024);
|
|
67
|
+
return {
|
|
68
|
+
totalGb: Math.round(totalGb * 10) / 10,
|
|
69
|
+
freeGb: Math.round(freeGb * 10) / 10,
|
|
70
|
+
usedGb: Math.round((totalGb - freeGb) * 10) / 10,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
const { stdout: fsStdout } = await execFileAsync('wmic', ['logicaldisk', 'where', `DeviceID="${driveLetter}:"`, 'get', 'FreeSpace,Size', '/format:list'], { windowsHide: true, timeout: 5000 });
|
|
74
|
+
const lines = fsStdout.split('\n');
|
|
75
|
+
let free = 0;
|
|
76
|
+
let size = 0;
|
|
77
|
+
for (const line of lines) {
|
|
78
|
+
if (line.startsWith('FreeSpace='))
|
|
79
|
+
free = parseInt(line.split('=')[1] || '0', 10);
|
|
80
|
+
if (line.startsWith('Size='))
|
|
81
|
+
size = parseInt(line.split('=')[1] || '0', 10);
|
|
82
|
+
}
|
|
83
|
+
if (size > 0) {
|
|
84
|
+
const totalGb = size / (1024 * 1024 * 1024);
|
|
85
|
+
const freeGb = free / (1024 * 1024 * 1024);
|
|
86
|
+
return {
|
|
87
|
+
totalGb: Math.round(totalGb * 10) / 10,
|
|
88
|
+
freeGb: Math.round(freeGb * 10) / 10,
|
|
89
|
+
usedGb: Math.round((totalGb - freeGb) * 10) / 10,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
const { stdout } = await execFileAsync('df', ['-k', workspaceRoot], { timeout: 5000 });
|
|
95
|
+
const lines = stdout.trim().split('\n');
|
|
96
|
+
if (lines.length >= 2) {
|
|
97
|
+
const parts = lines[1].trim().split(/\s+/).filter(Boolean);
|
|
98
|
+
const totalKb = parseInt(parts[1] || '0', 10);
|
|
99
|
+
const usedKb = parseInt(parts[2] || '0', 10);
|
|
100
|
+
const freeKb = parseInt(parts[3] || '0', 10);
|
|
101
|
+
return {
|
|
102
|
+
totalGb: Math.round((totalKb / (1024 * 1024)) * 10) / 10,
|
|
103
|
+
freeGb: Math.round((freeKb / (1024 * 1024)) * 10) / 10,
|
|
104
|
+
usedGb: Math.round((usedKb / (1024 * 1024)) * 10) / 10,
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (err) {
|
|
110
|
+
// Fall back to 0
|
|
111
|
+
}
|
|
112
|
+
return { totalGb: 0, freeGb: 0, usedGb: 0 };
|
|
113
|
+
}
|
|
114
|
+
export const sysopsTools = {
|
|
115
|
+
listOpenPorts: tool({
|
|
116
|
+
description: 'List all open/listening TCP ports on the local system, including PIDs and process names. Works on Windows, macOS, and Linux.',
|
|
117
|
+
inputSchema: z.object({}),
|
|
118
|
+
execute: async () => {
|
|
119
|
+
emitProgress({ type: 'fetch:start', label: 'Listing open ports' });
|
|
120
|
+
try {
|
|
121
|
+
if (process.platform === 'win32') {
|
|
122
|
+
const script = `
|
|
123
|
+
Get-NetTCPConnection -State Listen -ErrorAction SilentlyContinue | ForEach-Object {
|
|
124
|
+
$proc = Get-Process -Id $_.OwningProcess -ErrorAction SilentlyContinue
|
|
125
|
+
[PSCustomObject]@{
|
|
126
|
+
localAddress = $_.LocalAddress
|
|
127
|
+
localPort = $_.LocalPort
|
|
128
|
+
state = $_.State.ToString()
|
|
129
|
+
pid = $_.OwningProcess
|
|
130
|
+
processName = if ($proc) { $proc.Name } else { "Unknown" }
|
|
131
|
+
}
|
|
132
|
+
} | ConvertTo-Json -Compress
|
|
133
|
+
`;
|
|
134
|
+
const { stdout } = await execFileAsync('powershell.exe', ['-NoProfile', '-Command', script], { windowsHide: true, timeout: 10000 });
|
|
135
|
+
const cleaned = stdout.trim();
|
|
136
|
+
if (!cleaned) {
|
|
137
|
+
emitProgress({ type: 'fetch:end', label: 'Open ports listed', detail: 'None found' });
|
|
138
|
+
return { ports: [] };
|
|
139
|
+
}
|
|
140
|
+
let parsed = JSON.parse(cleaned);
|
|
141
|
+
if (!Array.isArray(parsed)) {
|
|
142
|
+
parsed = [parsed];
|
|
143
|
+
}
|
|
144
|
+
emitProgress({ type: 'fetch:end', label: 'Open ports listed', detail: `Found ${parsed.length} ports` });
|
|
145
|
+
return { ports: parsed };
|
|
146
|
+
}
|
|
147
|
+
else {
|
|
148
|
+
let ports = [];
|
|
149
|
+
if (await commandExists('lsof')) {
|
|
150
|
+
const { stdout } = await execFileAsync('lsof', ['-iTCP', '-sTCP:LISTEN', '-P', '-n'], { timeout: 10000 });
|
|
151
|
+
const lines = stdout.trim().split('\n').slice(1);
|
|
152
|
+
for (const line of lines) {
|
|
153
|
+
const parts = line.split(/\s+/).filter(Boolean);
|
|
154
|
+
if (parts.length >= 9) {
|
|
155
|
+
const processName = parts[0] || 'Unknown';
|
|
156
|
+
const pid = parseInt(parts[1] || '0', 10);
|
|
157
|
+
const nameCol = parts[8] || '';
|
|
158
|
+
const lastColon = nameCol.lastIndexOf(':');
|
|
159
|
+
let localPort = 0;
|
|
160
|
+
let localAddress = '*';
|
|
161
|
+
if (lastColon !== -1) {
|
|
162
|
+
localAddress = nameCol.slice(0, lastColon);
|
|
163
|
+
localPort = parseInt(nameCol.slice(lastColon + 1), 10) || 0;
|
|
164
|
+
}
|
|
165
|
+
ports.push({ localAddress, localPort, pid, processName });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
else if (await commandExists('netstat')) {
|
|
170
|
+
const { stdout } = await execFileAsync('netstat', ['-lntp'], { timeout: 10000 });
|
|
171
|
+
const lines = stdout.trim().split('\n').filter(l => l.includes('LISTEN'));
|
|
172
|
+
for (const line of lines) {
|
|
173
|
+
const parts = line.split(/\s+/).filter(Boolean);
|
|
174
|
+
if (parts.length >= 6) {
|
|
175
|
+
const localCol = parts[3] || '';
|
|
176
|
+
const lastColon = localCol.lastIndexOf(':');
|
|
177
|
+
const localPort = lastColon !== -1 ? parseInt(localCol.slice(lastColon + 1), 10) || 0 : 0;
|
|
178
|
+
const localAddress = lastColon !== -1 ? localCol.slice(0, lastColon) : localCol;
|
|
179
|
+
const pidCol = parts[6] || '';
|
|
180
|
+
const [pidStr, processName] = pidCol.split('/');
|
|
181
|
+
const pid = parseInt(pidStr || '0', 10);
|
|
182
|
+
ports.push({
|
|
183
|
+
localAddress,
|
|
184
|
+
localPort,
|
|
185
|
+
pid,
|
|
186
|
+
processName: processName || 'Unknown',
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
emitProgress({ type: 'fetch:end', label: 'Open ports listed', detail: `Found ${ports.length} ports` });
|
|
192
|
+
return { ports };
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
catch (error) {
|
|
196
|
+
emitProgress({ type: 'tool:error', label: 'List open ports failed', detail: error.message });
|
|
197
|
+
return { error: 'Failed to list open ports.', rawError: error.message };
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
}),
|
|
201
|
+
pingHost: tool({
|
|
202
|
+
description: 'Send ICMP Echo requests to a host to check network latency and packet loss. Works on Windows, macOS, and Linux.',
|
|
203
|
+
inputSchema: z.object({
|
|
204
|
+
host: z.string().min(1).describe('The hostname or IP address to ping (e.g., "google.com", "8.8.8.8").'),
|
|
205
|
+
}),
|
|
206
|
+
execute: async ({ host }) => {
|
|
207
|
+
emitProgress({ type: 'fetch:start', label: 'Pinging host', detail: host });
|
|
208
|
+
try {
|
|
209
|
+
const isWin = process.platform === 'win32';
|
|
210
|
+
const cmd = 'ping';
|
|
211
|
+
const args = isWin ? ['-n', '3', host] : ['-c', '3', host];
|
|
212
|
+
const { stdout } = await execFileAsync(cmd, args, { windowsHide: true, timeout: 10000 });
|
|
213
|
+
emitProgress({ type: 'fetch:end', label: 'Ping complete', detail: host });
|
|
214
|
+
return {
|
|
215
|
+
host,
|
|
216
|
+
success: true,
|
|
217
|
+
output: stdout.trim(),
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
emitProgress({ type: 'tool:error', label: 'Ping failed', detail: error.message });
|
|
222
|
+
return {
|
|
223
|
+
host,
|
|
224
|
+
success: false,
|
|
225
|
+
error: `Ping to "${host}" failed or timed out.`,
|
|
226
|
+
rawError: error.message,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
}),
|
|
231
|
+
traceRoute: tool({
|
|
232
|
+
description: 'Trace the routing path packets take to reach a host. Works on Windows (tracert), macOS, and Linux (traceroute).',
|
|
233
|
+
inputSchema: z.object({
|
|
234
|
+
host: z.string().min(1).describe('The hostname or IP address to trace route to.'),
|
|
235
|
+
}),
|
|
236
|
+
execute: async ({ host }) => {
|
|
237
|
+
emitProgress({ type: 'fetch:start', label: 'Tracing route', detail: host });
|
|
238
|
+
try {
|
|
239
|
+
const isWin = process.platform === 'win32';
|
|
240
|
+
const cmd = isWin ? 'tracert' : 'traceroute';
|
|
241
|
+
const args = isWin ? ['-h', '15', host] : ['-m', '15', host];
|
|
242
|
+
const { stdout } = await execFileAsync(cmd, args, { windowsHide: true, timeout: 30000 });
|
|
243
|
+
emitProgress({ type: 'fetch:end', label: 'Traceroute complete', detail: host });
|
|
244
|
+
return {
|
|
245
|
+
host,
|
|
246
|
+
output: stdout.trim(),
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
catch (error) {
|
|
250
|
+
emitProgress({ type: 'tool:error', label: 'Traceroute failed', detail: error.message });
|
|
251
|
+
return {
|
|
252
|
+
host,
|
|
253
|
+
error: `Traceroute to "${host}" failed or timed out.`,
|
|
254
|
+
rawError: error.message,
|
|
255
|
+
};
|
|
256
|
+
}
|
|
257
|
+
},
|
|
258
|
+
}),
|
|
259
|
+
getDatabaseSchema: tool({
|
|
260
|
+
description: 'Inspect a SQLite database file and return its schema tables and definitions. Multi-OS with built-in SQLite CLI and Python fallbacks.',
|
|
261
|
+
inputSchema: z.object({
|
|
262
|
+
databasePath: z.string().min(1).describe('Relative or absolute path to the SQLite database file in the workspace.'),
|
|
263
|
+
}),
|
|
264
|
+
execute: async ({ databasePath }) => {
|
|
265
|
+
emitProgress({ type: 'fetch:start', label: 'Querying DB schema', detail: databasePath });
|
|
266
|
+
const root = resolveWorkspaceRoot();
|
|
267
|
+
const resolvedPath = path.isAbsolute(databasePath) ? databasePath : path.join(root, databasePath);
|
|
268
|
+
if (!existsSync(resolvedPath)) {
|
|
269
|
+
emitProgress({ type: 'fetch:end', label: 'DB schema failed', detail: 'File not found' });
|
|
270
|
+
return { error: `Database file not found at path: ${databasePath}` };
|
|
271
|
+
}
|
|
272
|
+
if (await commandExists('sqlite3')) {
|
|
273
|
+
try {
|
|
274
|
+
const { stdout } = await execFileAsync('sqlite3', [resolvedPath, '.schema'], { windowsHide: true, timeout: 10000 });
|
|
275
|
+
emitProgress({ type: 'fetch:end', label: 'DB schema retrieved', detail: databasePath });
|
|
276
|
+
return {
|
|
277
|
+
databasePath,
|
|
278
|
+
method: 'sqlite3-cli',
|
|
279
|
+
schema: stdout.trim() || 'Database is empty (no tables found).',
|
|
280
|
+
};
|
|
281
|
+
}
|
|
282
|
+
catch { }
|
|
283
|
+
}
|
|
284
|
+
const pythonCmd = await commandExists('python') ? 'python' : (await commandExists('python3') ? 'python3' : null);
|
|
285
|
+
if (pythonCmd) {
|
|
286
|
+
try {
|
|
287
|
+
const script = `
|
|
288
|
+
import sqlite3, sys, json
|
|
289
|
+
try:
|
|
290
|
+
conn = sqlite3.connect(sys.argv[1])
|
|
291
|
+
cursor = conn.cursor()
|
|
292
|
+
cursor.execute("SELECT name, sql FROM sqlite_master WHERE type='table';")
|
|
293
|
+
tables = [{'name': r[0], 'sql': r[1]} for r in cursor.fetchall() if r[1]]
|
|
294
|
+
print(json.dumps({'success': True, 'tables': tables}))
|
|
295
|
+
except Exception as e:
|
|
296
|
+
print(json.dumps({'success': False, 'error': str(e)}))
|
|
297
|
+
`;
|
|
298
|
+
const { stdout } = await execFileAsync(pythonCmd, ['-c', script, resolvedPath], { windowsHide: true, timeout: 10000 });
|
|
299
|
+
const parsed = JSON.parse(stdout.trim());
|
|
300
|
+
if (parsed.success) {
|
|
301
|
+
const schemaLines = parsed.tables.map((t) => `${t.sql};`).join('\n\n');
|
|
302
|
+
emitProgress({ type: 'fetch:end', label: 'DB schema retrieved', detail: databasePath });
|
|
303
|
+
return {
|
|
304
|
+
databasePath,
|
|
305
|
+
method: 'python-sqlite3',
|
|
306
|
+
schema: schemaLines || 'Database is empty (no tables found).',
|
|
307
|
+
tables: parsed.tables.map((t) => t.name),
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
catch { }
|
|
312
|
+
}
|
|
313
|
+
emitProgress({ type: 'tool:error', label: 'DB schema failed', detail: 'No SQLite readers found' });
|
|
314
|
+
return {
|
|
315
|
+
error: 'Failed to inspect database schema. Please install the `sqlite3` CLI utility or `python` on your system to enable inspection.',
|
|
316
|
+
};
|
|
317
|
+
},
|
|
318
|
+
}),
|
|
319
|
+
runDatabaseQuery: tool({
|
|
320
|
+
description: 'Execute raw SQL queries against a local SQLite database in the workspace. Transaction-safe, with capped result limits. Works on Windows, macOS, and Linux.',
|
|
321
|
+
inputSchema: z.object({
|
|
322
|
+
databasePath: z.string().min(1).describe('Relative or absolute path to the SQLite database file in the workspace.'),
|
|
323
|
+
sql: z.string().min(1).describe('The SQL query or statement to run (e.g., "SELECT * FROM users LIMIT 10").'),
|
|
324
|
+
}),
|
|
325
|
+
execute: async ({ databasePath, sql }) => {
|
|
326
|
+
emitProgress({ type: 'tool:start', label: 'Executing DB query', detail: databasePath });
|
|
327
|
+
const root = resolveWorkspaceRoot();
|
|
328
|
+
const resolvedPath = path.isAbsolute(databasePath) ? databasePath : path.join(root, databasePath);
|
|
329
|
+
if (!existsSync(resolvedPath)) {
|
|
330
|
+
emitProgress({ type: 'tool:error', label: 'DB query failed', detail: 'File not found' });
|
|
331
|
+
return { error: `Database file not found at path: ${databasePath}` };
|
|
332
|
+
}
|
|
333
|
+
let query = sql.trim();
|
|
334
|
+
if (!query.endsWith(';')) {
|
|
335
|
+
query += ';';
|
|
336
|
+
}
|
|
337
|
+
if (query.toUpperCase().startsWith('SELECT') && !query.toUpperCase().includes('LIMIT')) {
|
|
338
|
+
query = query.slice(0, -1) + ' LIMIT 100;';
|
|
339
|
+
}
|
|
340
|
+
const pythonCmd = await commandExists('python') ? 'python' : (await commandExists('python3') ? 'python3' : null);
|
|
341
|
+
if (pythonCmd) {
|
|
342
|
+
try {
|
|
343
|
+
const script = `
|
|
344
|
+
import sqlite3, sys, json
|
|
345
|
+
try:
|
|
346
|
+
conn = sqlite3.connect(sys.argv[1])
|
|
347
|
+
conn.row_factory = sqlite3.Row
|
|
348
|
+
cursor = conn.cursor()
|
|
349
|
+
cursor.execute(sys.argv[2])
|
|
350
|
+
|
|
351
|
+
if cursor.description:
|
|
352
|
+
rows = cursor.fetchall()
|
|
353
|
+
results = [dict(row) for row in rows]
|
|
354
|
+
print(json.dumps({'success': True, 'type': 'query', 'results': results}))
|
|
355
|
+
else:
|
|
356
|
+
conn.commit()
|
|
357
|
+
print(json.dumps({'success': True, 'type': 'execute', 'rows_affected': cursor.rowcount}))
|
|
358
|
+
except Exception as e:
|
|
359
|
+
print(json.dumps({'success': False, 'error': str(e)}))
|
|
360
|
+
`;
|
|
361
|
+
const { stdout } = await execFileAsync(pythonCmd, ['-c', script, resolvedPath, query], { windowsHide: true, timeout: 15000 });
|
|
362
|
+
const parsed = JSON.parse(stdout.trim());
|
|
363
|
+
if (parsed.success) {
|
|
364
|
+
emitProgress({ type: 'tool:end', label: 'DB query successful', detail: parsed.type });
|
|
365
|
+
return parsed;
|
|
366
|
+
}
|
|
367
|
+
else {
|
|
368
|
+
emitProgress({ type: 'tool:error', label: 'DB query failed', detail: parsed.error });
|
|
369
|
+
return { error: `SQL execution error: ${parsed.error}` };
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
catch (err) {
|
|
373
|
+
// Fall back
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
if (await commandExists('sqlite3')) {
|
|
377
|
+
try {
|
|
378
|
+
const { stdout } = await execFileAsync('sqlite3', ['-header', '-json', resolvedPath, query], { windowsHide: true, timeout: 15000 });
|
|
379
|
+
emitProgress({ type: 'tool:end', label: 'DB query successful (sqlite3)' });
|
|
380
|
+
try {
|
|
381
|
+
const results = JSON.parse(stdout.trim() || '[]');
|
|
382
|
+
return { success: true, type: 'query', results };
|
|
383
|
+
}
|
|
384
|
+
catch {
|
|
385
|
+
return {
|
|
386
|
+
success: true,
|
|
387
|
+
type: 'raw',
|
|
388
|
+
output: stdout.trim() || 'Statement executed successfully (no results).',
|
|
389
|
+
};
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
catch (cliError) {
|
|
393
|
+
emitProgress({ type: 'tool:error', label: 'DB query failed', detail: cliError.message });
|
|
394
|
+
return { error: `SQL execution error: ${cliError.message}` };
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
emitProgress({ type: 'tool:error', label: 'DB query failed', detail: 'No SQLite executors found' });
|
|
398
|
+
return {
|
|
399
|
+
error: 'Failed to execute query. Please install the `sqlite3` CLI utility or `python` on your system to enable SQLite operations.',
|
|
400
|
+
};
|
|
401
|
+
},
|
|
402
|
+
}),
|
|
403
|
+
listSystemProcesses: tool({
|
|
404
|
+
description: 'List active system processes with PIDs, names, CPU, and Memory usage metrics. Works on Windows, macOS, and Linux.',
|
|
405
|
+
inputSchema: z.object({
|
|
406
|
+
sortBy: z.enum(['cpu', 'memory', 'pid']).optional().default('memory').describe('Metric to sort processes by.'),
|
|
407
|
+
limit: z.number().int().min(1).max(500).optional().default(30).describe('Maximum number of processes to return.'),
|
|
408
|
+
filterName: z.string().optional().describe('Filter processes by containing name (case-insensitive).'),
|
|
409
|
+
}),
|
|
410
|
+
execute: async ({ sortBy, limit, filterName }) => {
|
|
411
|
+
emitProgress({ type: 'fetch:start', label: 'Listing system processes' });
|
|
412
|
+
try {
|
|
413
|
+
let processes = [];
|
|
414
|
+
if (process.platform === 'win32') {
|
|
415
|
+
const script = `
|
|
416
|
+
Get-Process -ErrorAction SilentlyContinue | ForEach-Object {
|
|
417
|
+
[PSCustomObject]@{
|
|
418
|
+
pid = $_.Id
|
|
419
|
+
name = $_.ProcessName
|
|
420
|
+
cpu = if ($_.CPU) { [Math]::Round($_.CPU, 1) } else { 0 }
|
|
421
|
+
memory = [Math]::Round($_.WorkingSet64 / 1MB, 1)
|
|
422
|
+
}
|
|
423
|
+
} | ConvertTo-Json -Compress
|
|
424
|
+
`;
|
|
425
|
+
const { stdout } = await execFileAsync('powershell.exe', ['-NoProfile', '-Command', script], { windowsHide: true, timeout: 10000 });
|
|
426
|
+
const cleaned = stdout.trim();
|
|
427
|
+
if (cleaned) {
|
|
428
|
+
let parsed = JSON.parse(cleaned);
|
|
429
|
+
if (!Array.isArray(parsed)) {
|
|
430
|
+
parsed = [parsed];
|
|
431
|
+
}
|
|
432
|
+
processes = parsed.map((p) => ({
|
|
433
|
+
pid: p.pid || 0,
|
|
434
|
+
name: p.name || 'Unknown',
|
|
435
|
+
cpu: p.cpu || 0,
|
|
436
|
+
memory: p.memory || 0,
|
|
437
|
+
}));
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
else {
|
|
441
|
+
const { stdout } = await execFileAsync('ps', ['-A', '-o', 'pid,pcpu,pmem,comm'], { timeout: 10000 });
|
|
442
|
+
const lines = stdout.trim().split('\n').slice(1);
|
|
443
|
+
for (const line of lines) {
|
|
444
|
+
const parts = line.trim().split(/\s+/).filter(Boolean);
|
|
445
|
+
if (parts.length >= 4) {
|
|
446
|
+
const pid = parseInt(parts[0] || '0', 10);
|
|
447
|
+
const cpu = parseFloat(parts[1] || '0');
|
|
448
|
+
const memory = parseFloat(parts[2] || '0');
|
|
449
|
+
const namePath = parts.slice(3).join(' ');
|
|
450
|
+
const name = path.basename(namePath);
|
|
451
|
+
processes.push({ pid, name, cpu, memory });
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
if (filterName) {
|
|
456
|
+
const lowerFilter = filterName.toLowerCase();
|
|
457
|
+
processes = processes.filter((p) => p.name.toLowerCase().includes(lowerFilter));
|
|
458
|
+
}
|
|
459
|
+
processes.sort((a, b) => {
|
|
460
|
+
if (sortBy === 'cpu')
|
|
461
|
+
return b.cpu - a.cpu;
|
|
462
|
+
if (sortBy === 'memory')
|
|
463
|
+
return b.memory - a.memory;
|
|
464
|
+
return b.pid - a.pid;
|
|
465
|
+
});
|
|
466
|
+
const results = processes.slice(0, limit);
|
|
467
|
+
emitProgress({ type: 'fetch:end', label: 'System processes listed', detail: `Returned ${results.length} process(es)` });
|
|
468
|
+
return { processes: results };
|
|
469
|
+
}
|
|
470
|
+
catch (error) {
|
|
471
|
+
emitProgress({ type: 'tool:error', label: 'List processes failed', detail: error.message });
|
|
472
|
+
return { error: 'Failed to list system processes.', rawError: error.message };
|
|
473
|
+
}
|
|
474
|
+
},
|
|
475
|
+
}),
|
|
476
|
+
killSystemProcess: tool({
|
|
477
|
+
description: 'Terminate a local system process by process ID (PID), process name, or net port attachment. Works on Windows, macOS, and Linux.',
|
|
478
|
+
inputSchema: z.object({
|
|
479
|
+
pid: z.number().int().min(1).optional().describe('The process ID to kill.'),
|
|
480
|
+
name: z.string().optional().describe('The process name to kill (e.g. "node", "chrome"). Will kill all matching instances.'),
|
|
481
|
+
port: z.number().int().min(1).max(65535).optional().describe('Kill whatever process is currently listening on this local port (e.g. 3000, 8080).'),
|
|
482
|
+
force: z.boolean().optional().default(true).describe('If true, sends a SIGKILL or force taskkill.'),
|
|
483
|
+
}),
|
|
484
|
+
execute: async ({ pid, name, port, force }) => {
|
|
485
|
+
if (!pid && !name && !port) {
|
|
486
|
+
return { error: 'Either "pid", "name", or "port" must be provided to kill a process.' };
|
|
487
|
+
}
|
|
488
|
+
emitProgress({ type: 'tool:start', label: 'Killing system process', detail: pid ? `PID ${pid}` : name ? `name "${name}"` : `port :${port}` });
|
|
489
|
+
try {
|
|
490
|
+
const isWin = process.platform === 'win32';
|
|
491
|
+
let targetPids = [];
|
|
492
|
+
// If port is specified, scan for the listening PID(s)
|
|
493
|
+
if (port) {
|
|
494
|
+
emitProgress({ type: 'step', label: `Scanning process occupying port ${port}` });
|
|
495
|
+
if (isWin) {
|
|
496
|
+
const script = `
|
|
497
|
+
Get-NetTCPConnection -LocalPort ${port} -State Listen -ErrorAction SilentlyContinue | ForEach-Object {
|
|
498
|
+
$_.OwningProcess
|
|
499
|
+
} | ConvertTo-Json -Compress
|
|
500
|
+
`;
|
|
501
|
+
const { stdout } = await execFileAsync('powershell.exe', ['-NoProfile', '-Command', script], { windowsHide: true, timeout: 5000 });
|
|
502
|
+
const cleaned = stdout.trim();
|
|
503
|
+
if (cleaned) {
|
|
504
|
+
const parsed = JSON.parse(cleaned);
|
|
505
|
+
targetPids = Array.isArray(parsed) ? parsed.map(Number) : [Number(parsed)];
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
else {
|
|
509
|
+
if (await commandExists('lsof')) {
|
|
510
|
+
const { stdout } = await execFileAsync('lsof', ['-t', '-i', `:${port}`], { timeout: 5000 });
|
|
511
|
+
targetPids = stdout.trim().split(/\s+/).map(Number).filter(Boolean);
|
|
512
|
+
}
|
|
513
|
+
else if (await commandExists('netstat')) {
|
|
514
|
+
const { stdout } = await execFileAsync('netstat', ['-lntp'], { timeout: 5000 });
|
|
515
|
+
const lines = stdout.trim().split('\n');
|
|
516
|
+
for (const line of lines) {
|
|
517
|
+
if (line.includes(`:${port}`) && line.includes('LISTEN')) {
|
|
518
|
+
const parts = line.split(/\s+/).filter(Boolean);
|
|
519
|
+
const pidCol = parts[6] || '';
|
|
520
|
+
const pidVal = parseInt(pidCol.split('/')[0] || '0', 10);
|
|
521
|
+
if (pidVal)
|
|
522
|
+
targetPids.push(pidVal);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
if (targetPids.length === 0) {
|
|
528
|
+
emitProgress({ type: 'tool:error', label: 'Kill process failed', detail: `No process owns port ${port}` });
|
|
529
|
+
return { success: false, error: `No process detected listening on port ${port}.` };
|
|
530
|
+
}
|
|
531
|
+
emitProgress({ type: 'step', label: `Resolved port ${port} to PID(s): ${targetPids.join(', ')}` });
|
|
532
|
+
}
|
|
533
|
+
// If we resolved PIDs from port or got one directly, kill them
|
|
534
|
+
if (pid) {
|
|
535
|
+
targetPids.push(pid);
|
|
536
|
+
}
|
|
537
|
+
if (targetPids.length > 0) {
|
|
538
|
+
const uniquePids = [...new Set(targetPids)];
|
|
539
|
+
for (const targetPid of uniquePids) {
|
|
540
|
+
if (isWin) {
|
|
541
|
+
const args = force ? ['/F', '/PID', String(targetPid)] : ['/PID', String(targetPid)];
|
|
542
|
+
await execFileAsync('taskkill', args, { windowsHide: true, timeout: 5000 });
|
|
543
|
+
}
|
|
544
|
+
else {
|
|
545
|
+
const args = force ? ['-9', String(targetPid)] : [String(targetPid)];
|
|
546
|
+
await execFileAsync('kill', args, { timeout: 5000 });
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
emitProgress({ type: 'tool:end', label: 'Process killed successfully', detail: `PID(s): ${uniquePids.join(', ')}` });
|
|
550
|
+
return { success: true, killedPids: uniquePids };
|
|
551
|
+
}
|
|
552
|
+
else if (name) {
|
|
553
|
+
if (isWin) {
|
|
554
|
+
const exeName = name.toLowerCase().endsWith('.exe') ? name : `${name}.exe`;
|
|
555
|
+
const args = force ? ['/F', '/IM', exeName] : ['/IM', exeName];
|
|
556
|
+
await execFileAsync('taskkill', args, { windowsHide: true, timeout: 5000 });
|
|
557
|
+
}
|
|
558
|
+
else {
|
|
559
|
+
if (await commandExists('pkill')) {
|
|
560
|
+
const args = force ? ['-9', '-f', name] : ['-f', name];
|
|
561
|
+
await execFileAsync('pkill', args, { timeout: 5000 });
|
|
562
|
+
}
|
|
563
|
+
else {
|
|
564
|
+
const args = force ? ['-9', name] : [name];
|
|
565
|
+
await execFileAsync('killall', args, { timeout: 5000 });
|
|
566
|
+
}
|
|
567
|
+
}
|
|
568
|
+
emitProgress({ type: 'tool:end', label: 'Processes killed successfully', detail: name });
|
|
569
|
+
return { success: true, name };
|
|
570
|
+
}
|
|
571
|
+
return { error: 'Invalid arguments' };
|
|
572
|
+
}
|
|
573
|
+
catch (error) {
|
|
574
|
+
emitProgress({ type: 'tool:error', label: 'Kill process failed', detail: error.message });
|
|
575
|
+
return {
|
|
576
|
+
success: false,
|
|
577
|
+
error: `Failed to terminate process.`,
|
|
578
|
+
rawError: error.message,
|
|
579
|
+
};
|
|
580
|
+
}
|
|
581
|
+
},
|
|
582
|
+
}),
|
|
583
|
+
getSystemMetrics: tool({
|
|
584
|
+
description: 'Retrieve real-time telemetry metrics of the host machine (CPU usage, memory allocation, workspace disk space, and OS meta-data). Works on Windows, macOS, and Linux.',
|
|
585
|
+
inputSchema: z.object({}),
|
|
586
|
+
execute: async () => {
|
|
587
|
+
emitProgress({ type: 'fetch:start', label: 'Collecting system metrics' });
|
|
588
|
+
try {
|
|
589
|
+
const platform = process.platform;
|
|
590
|
+
const arch = os.arch();
|
|
591
|
+
const release = os.release();
|
|
592
|
+
const uptime = os.uptime();
|
|
593
|
+
const osName = os.type();
|
|
594
|
+
// 1. CPU Metrics
|
|
595
|
+
emitProgress({ type: 'step', label: 'Sampling CPU utilization' });
|
|
596
|
+
const cpuUsage = await sampleCpuUsage();
|
|
597
|
+
// 2. Memory Metrics
|
|
598
|
+
const totalMemGb = Math.round((os.totalmem() / (1024 * 1024 * 1024)) * 10) / 10;
|
|
599
|
+
const freeMemGb = Math.round((os.freemem() / (1024 * 1024 * 1024)) * 10) / 10;
|
|
600
|
+
const usedMemGb = Math.round((totalMemGb - freeMemGb) * 10) / 10;
|
|
601
|
+
// 3. Disk Metrics for Workspace Root
|
|
602
|
+
const wsRoot = resolveWorkspaceRoot();
|
|
603
|
+
emitProgress({ type: 'step', label: 'Querying workspace disk allocation' });
|
|
604
|
+
const disk = await getDiskSpace(wsRoot);
|
|
605
|
+
const metrics = {
|
|
606
|
+
os: {
|
|
607
|
+
name: osName,
|
|
608
|
+
platform,
|
|
609
|
+
release,
|
|
610
|
+
architecture: arch,
|
|
611
|
+
uptimeSeconds: uptime,
|
|
612
|
+
uptimeHours: Math.round((uptime / 3600) * 10) / 10,
|
|
613
|
+
},
|
|
614
|
+
cpu: {
|
|
615
|
+
activeUtilizationPercent: cpuUsage,
|
|
616
|
+
cores: os.cpus().length,
|
|
617
|
+
model: os.cpus()[0]?.model || 'Unknown',
|
|
618
|
+
},
|
|
619
|
+
memory: {
|
|
620
|
+
totalGb: totalMemGb,
|
|
621
|
+
freeGb: freeMemGb,
|
|
622
|
+
usedGb: usedMemGb,
|
|
623
|
+
utilizationPercent: Math.round(((totalMemGb - freeMemGb) / totalMemGb) * 1000) / 10,
|
|
624
|
+
},
|
|
625
|
+
disk: {
|
|
626
|
+
workspacePath: wsRoot,
|
|
627
|
+
totalGb: disk.totalGb,
|
|
628
|
+
freeGb: disk.freeGb,
|
|
629
|
+
usedGb: disk.usedGb,
|
|
630
|
+
utilizationPercent: disk.totalGb > 0 ? Math.round((disk.usedGb / disk.totalGb) * 1000) / 10 : 0,
|
|
631
|
+
},
|
|
632
|
+
};
|
|
633
|
+
emitProgress({ type: 'fetch:end', label: 'System metrics collected' });
|
|
634
|
+
return { success: true, metrics };
|
|
635
|
+
}
|
|
636
|
+
catch (error) {
|
|
637
|
+
emitProgress({ type: 'tool:error', label: 'System metrics collection failed', detail: error.message });
|
|
638
|
+
return { success: false, error: 'Failed to retrieve system metrics.', rawError: error.message };
|
|
639
|
+
}
|
|
640
|
+
},
|
|
641
|
+
}),
|
|
642
|
+
};
|
|
643
|
+
//# sourceMappingURL=sysops.tool.js.map
|