Files
IdeaSDK/docs/services.md

5.0 KiB

Services

ctx.services is the stable public host facade. It is available to plugins that declare ui or tooling capabilities.

{
  "capabilities": ["ui", "tooling"]
}

Workspace

services.workspace reads the focused/current project, project context and project-owned files. Paths are relative to the project root; hosts reject absolute paths and traversal outside the workspace.

Key APIs:

  • getCurrentProject()
  • getProjectRoot(projectId?)
  • readProjectContext(projectId?)
  • updateProjectContext(content, projectId?)
  • readTextFile(path, projectId?)
  • writeTextFile(path, content, projectId?)
  • readBinaryFile(path, projectId?)
  • writeBinaryFile(path, bytes, projectId?)
  • listDirectory(path?, projectId?)
  • stat(path, projectId?)
  • watch(path, handler, projectId?)
  • queryStructure(query?)
  • execTool(request)

Short external tools

services.workspace.execTool() runs a short external executable already available to the host. It is generic: IdeA does not expose Git, SVN, formatter, or linter semantics. The plugin owns the arguments and parses the returned output.

const result = await ctx.services!.workspace.execTool({
  projectId,
  command: "tool",
  args: ["status", "--short"],
  cwd: ".",
  timeoutMs: 5_000,
  maxStdoutBytes: 256_000,
  maxStderrBytes: 64_000
});

The host passes command and args directly without a shell. The plugin must declare a matching permissions.workspaceExec.allow rule, be active for the project, and use a project-relative cwd. IdeA canonicalizes the cwd, bounds time/stdin/output/concurrency, exposes only an allowlisted environment, applies the project filesystem sandbox where supported, and audits metadata without captured stdout/stderr contents. This API returns output directly and never creates a visible Work/background-task entry.

Current host maxima are 30 seconds, 1,000,000 stdout bytes, 256,000 stderr bytes, and 64,000 stdin bytes. Requested output/time values above a maximum are clamped; zero is rejected. Output is returned as lossy UTF-8 with explicit truncation flags.

Tasks

services.tasks launches and inspects host-managed command tasks.

Use runCommand() only after preconditions are satisfied. ownerAgentId must be a real agent id when work belongs to an agent workflow.

runCommand() keeps its cwd project/workspace scoped: cwd must be a relative path under the project root. The host does not implicitly resolve command or args against the plugin package. Use the absolute ctx.pluginRoot supplied at activation time to construct an explicit path to a packaged script, and pass that path as command or as an argument to its interpreter. Treat package files as read-only. Unlike manifest-declared MCP servers, runCommand() does not substitute ${pluginRoot} or ${appDataDir}.

const script = `${ctx.pluginRoot.replace(/[\\/]+$/, "")}/scripts/check.mjs`;
await ctx.services.tasks.runCommand({
  projectId,
  ownerAgentId,
  label: "Run packaged check",
  command: "node",
  args: [script],
  cwd: "."
});

This task example uses node as a host executable visible to the task environment. That is not the contract for contributes.mcpServers: MCP server command values are resolved by the plugin manifest rules documented in Manifest, where a bare command: "node" is package-relative unless external host-command handling is explicitly enabled.

Tooling

services.tooling.diagnose() checks executables, environment values and files from the host-controlled runtime.

Events

services.events.subscribe() provides best-effort bounded subscriptions to public plugin events such as workspace file changes and background task changes. Dispose subscriptions when no longer needed.

Config

services.config reads and updates structured JSON documents in project-owned locations. Use it for configuration the user expects to review/version.

Terminal

services.terminal opens, reattaches and closes terminal sessions:

  • open({ cwd?, rows?, cols?, onData? })
  • reattach(sessionId, { onData? })
  • close(sessionId)

Windows

services.windows.open({ layoutType, state? }) opens a detached OS window for one of the calling plugin's declared layout contributions. See Windows.

Resolving this promise means the window was opened or focused. Its alreadyOpen flag reports which happened; both outcomes are successful and a menu handler should return status: "opened". Do not gate a diagnostic window on optional tool availability when that window can present the unavailable state. A rejection means the window operation itself was impossible and may be logged or returned as status: "failed"; do not expose its raw error to users.

Scheduled tasks

Project scheduled tasks are exposed through native Tauri/HTTP commands and the native idea_scheduled_task_* MCP tools. They are intentionally not available as an activate(ctx) plugin service in V1, and plugins must not emulate them with system cron or repository-owned auto-executed files.