merge(sdk): intègre feature/sdk-package-doc — contrat command-and-feedback documenté (vert QA)
This commit is contained in:
40
README.md
40
README.md
@ -17,6 +17,40 @@ This first version intentionally stays small:
|
|||||||
- a lightweight manifest validator;
|
- a lightweight manifest validator;
|
||||||
- a minimal `examples/hello-plugin` plugin.
|
- a minimal `examples/hello-plugin` plugin.
|
||||||
|
|
||||||
|
## Command And Feedback Contract
|
||||||
|
|
||||||
|
Plugin menu actions follow one public contract:
|
||||||
|
|
||||||
|
```text
|
||||||
|
menu click -> registered command handler -> optional background task -> feedback surfaces
|
||||||
|
```
|
||||||
|
|
||||||
|
A menu item only names a command. The registered command handler owns all
|
||||||
|
precondition checks, task launch decisions and feedback. If a command
|
||||||
|
cannot or should not start work, return a small structured result such as
|
||||||
|
`{ status: "skipped", reason, message }` and log the same reason. That return
|
||||||
|
value is useful for programmatic callers, agents and future host surfaces; the
|
||||||
|
current human menu-click UI does not guarantee that handler return values are
|
||||||
|
shown to the user. Do not create a background task just to represent a skipped
|
||||||
|
command.
|
||||||
|
|
||||||
|
Use `ctx.services.tasks.runCommand()` only after required preconditions are
|
||||||
|
true: a focused project exists, the plugin has the `tooling` capability, required
|
||||||
|
executables/files/env are present, and a real `ownerAgentId` is available when
|
||||||
|
the result belongs to an agent workflow. `ownerAgentId` controls Work ownership,
|
||||||
|
cancellation and completion delivery; it must not be a placeholder in production
|
||||||
|
plugin code.
|
||||||
|
|
||||||
|
`recordOnly: true` records completion without waking the owner agent. It is not a
|
||||||
|
silent mode and it does not hide the task from surfaces that show Work state or
|
||||||
|
background-task events. If no task is launched, the baseline feedback surfaces
|
||||||
|
are the command result for programmatic callers and plugin logs; human-visible UI
|
||||||
|
feedback requires a host-supported surface, a real background task, or a
|
||||||
|
plugin-owned UI/file surface.
|
||||||
|
|
||||||
|
Canonical rules and examples live in
|
||||||
|
[`docs/commands-and-feedback.md`](docs/commands-and-feedback.md).
|
||||||
|
|
||||||
## Install
|
## Install
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
@ -236,8 +270,10 @@ export async function activate(ctx: ActivateContext): Promise<void> {
|
|||||||
```
|
```
|
||||||
|
|
||||||
`watch(path, handler, projectId?)` subscribes to public workspace file-change
|
`watch(path, handler, projectId?)` subscribes to public workspace file-change
|
||||||
events for the given relative path. It is best-effort and bounded: plugins should
|
events for the given relative path. It is best-effort and bounded: hosts may
|
||||||
handle missed events by refreshing their own derived state when needed.
|
reject it until workspace watching is implemented, and plugins must treat setup
|
||||||
|
failure as non-fatal. Plugins should also handle missed events by refreshing
|
||||||
|
their own derived state when needed.
|
||||||
|
|
||||||
### Project Structure
|
### Project Structure
|
||||||
|
|
||||||
|
|||||||
154
docs/commands-and-feedback.md
Normal file
154
docs/commands-and-feedback.md
Normal file
@ -0,0 +1,154 @@
|
|||||||
|
# Commands And Feedback
|
||||||
|
|
||||||
|
This document is the normative SDK contract for plugin commands that may launch
|
||||||
|
background work.
|
||||||
|
|
||||||
|
## Contract
|
||||||
|
|
||||||
|
Every human menu click follows this sequence:
|
||||||
|
|
||||||
|
```text
|
||||||
|
menu item -> command id -> registered command handler -> optional task -> feedback surfaces
|
||||||
|
```
|
||||||
|
|
||||||
|
- A manifest menu item declares a `command` id; it does not run tools directly.
|
||||||
|
- The command handler is the only place that decides whether work should start.
|
||||||
|
- A launched process is represented by a background task returned from
|
||||||
|
`ctx.services.tasks.runCommand()`.
|
||||||
|
- A skipped command is represented by the command handler return value and logs,
|
||||||
|
not by a fake task.
|
||||||
|
- Feedback objects must be stable enough for agents and programmatic callers to
|
||||||
|
parse, and their messages must be readable by humans.
|
||||||
|
- The current human menu-click UI does not guarantee display of a command
|
||||||
|
handler return value. Use logs, Work/task state or plugin-owned UI/files when
|
||||||
|
a human needs visible feedback today.
|
||||||
|
|
||||||
|
## Preconditions
|
||||||
|
|
||||||
|
Check preconditions before calling `runCommand()`:
|
||||||
|
|
||||||
|
- `ctx.services` exists. Plugins need the `tooling` capability for the service
|
||||||
|
facade.
|
||||||
|
- `ctx.services.workspace.getCurrentProject()` returned a project, or the caller
|
||||||
|
supplied a valid `projectId`.
|
||||||
|
- Required executables, environment variables and workspace files were validated,
|
||||||
|
preferably with `ctx.services.tooling.diagnose()`.
|
||||||
|
- `ownerAgentId` is a real agent id when the work is owned by an agent workflow.
|
||||||
|
Do not use all-zero placeholders in production.
|
||||||
|
- `cwd` is relative to the project root.
|
||||||
|
- `command` and `args` are separate values. Do not shell-join user input.
|
||||||
|
|
||||||
|
If any required precondition fails, return a skipped result:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
return {
|
||||||
|
status: "skipped",
|
||||||
|
reason: "missing-owner-agent",
|
||||||
|
message: "Configure an owner agent before launching the hello-plugin task."
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Feedback Surfaces
|
||||||
|
|
||||||
|
Command handlers should return one of these shapes, or a plugin-specific object
|
||||||
|
with equivalent fields:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
type CommandFeedback =
|
||||||
|
| { status: "skipped"; reason: string; message: string }
|
||||||
|
| { status: "launched"; taskId: string; state: string; message: string };
|
||||||
|
```
|
||||||
|
|
||||||
|
Use the same `status` vocabulary consistently:
|
||||||
|
|
||||||
|
- `skipped`: no background task was created.
|
||||||
|
- `launched`: a task was created; inspect the task state for later progress.
|
||||||
|
- `failed`: the handler itself failed before it could return normally.
|
||||||
|
|
||||||
|
Visible surfaces are intentionally distinct:
|
||||||
|
|
||||||
|
- Command return value: immediate feedback for programmatic callers, agents and
|
||||||
|
future host surfaces. It is not a guaranteed visible UI surface for current
|
||||||
|
human menu clicks.
|
||||||
|
- Plugin logs: diagnostics for developers and operators.
|
||||||
|
- Work/background-task surfaces: only for tasks actually launched through
|
||||||
|
`runCommand()`.
|
||||||
|
- Plugin layouts or files: optional plugin-owned user feedback.
|
||||||
|
|
||||||
|
`recordOnly: true` affects completion delivery to the owning agent. It does not
|
||||||
|
mean hidden, skipped or UI-silent. A record-only command task can still appear in
|
||||||
|
Work and can still emit background-task events.
|
||||||
|
|
||||||
|
## Best-Effort Watches
|
||||||
|
|
||||||
|
`ctx.services.workspace.watch()` is not a baseline precondition for commands.
|
||||||
|
The host may reject it until workspace watch support is delivered. Treat watch
|
||||||
|
setup as optional and non-fatal:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
try {
|
||||||
|
const watch = await ctx.services.workspace.watch(".ideai", refresh, project.id);
|
||||||
|
ctx.subscriptions.push(watch);
|
||||||
|
} catch (error) {
|
||||||
|
ctx.logger.info("workspace watch unavailable", { error });
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Commands that depend on fresh workspace state should refresh or re-read that
|
||||||
|
state when invoked instead of assuming a watch was installed at activation.
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
```ts
|
||||||
|
const project = await ctx.services?.workspace.getCurrentProject();
|
||||||
|
if (!project) {
|
||||||
|
return {
|
||||||
|
status: "skipped",
|
||||||
|
reason: "no-focused-project",
|
||||||
|
message: "Open a project before running this command."
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const ownerAgentId = await ctx.storage?.get<string>("myPlugin.ownerAgentId");
|
||||||
|
if (!ownerAgentId) {
|
||||||
|
return {
|
||||||
|
status: "skipped",
|
||||||
|
reason: "missing-owner-agent",
|
||||||
|
message: "Configure an owner agent before launching this task."
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const task = await ctx.services.tasks.runCommand({
|
||||||
|
projectId: project.id,
|
||||||
|
ownerAgentId,
|
||||||
|
label: "Run my tool",
|
||||||
|
command: "npm",
|
||||||
|
args: ["--version"],
|
||||||
|
cwd: ".",
|
||||||
|
recordOnly: true
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
status: "launched",
|
||||||
|
taskId: task.taskId,
|
||||||
|
state: task.state,
|
||||||
|
message: "Started Run my tool."
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Counterexample
|
||||||
|
|
||||||
|
Do not launch a shell command just to produce feedback:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
await ctx.services?.tasks.runCommand({
|
||||||
|
ownerAgentId: "00000000-0000-0000-0000-000000000000",
|
||||||
|
label: "Skipped: missing config",
|
||||||
|
command: "echo",
|
||||||
|
args: ["missing config"],
|
||||||
|
recordOnly: true
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
This creates misleading Work history, uses a placeholder owner and turns a
|
||||||
|
precondition failure into a fake task. Return `status: "skipped"` instead.
|
||||||
@ -6,7 +6,10 @@ It exercises the current plugin primitives end to end:
|
|||||||
|
|
||||||
- top-level menu: `Hello Plugin`;
|
- top-level menu: `Hello Plugin`;
|
||||||
- menu entry: `hello-plugin`;
|
- menu entry: `hello-plugin`;
|
||||||
- command: `hello-plugin`, returning `hello-world`;
|
- command: `hello-plugin`, returning readable feedback:
|
||||||
|
`{ status: "launched", taskId, state, message }` when it starts a background
|
||||||
|
task, or `{ status: "skipped", reason, message }` when a precondition is not
|
||||||
|
met;
|
||||||
- layout contribution: `hello-plugin.hello-world`, rendered as `hello-world`.
|
- layout contribution: `hello-plugin.hello-world`, rendered as `hello-world`.
|
||||||
- plugin-owned storage: activation count, command run count and initialization flag;
|
- plugin-owned storage: activation count, command run count and initialization flag;
|
||||||
- tooling capability: logs the focused workspace project when `ctx.services` is available.
|
- tooling capability: logs the focused workspace project when `ctx.services` is available.
|
||||||
@ -42,7 +45,15 @@ During activation the plugin logs:
|
|||||||
- successful registration of the `hello-plugin` command;
|
- successful registration of the `hello-plugin` command;
|
||||||
- successful registration of the `hello-plugin.hello-world` layout;
|
- successful registration of the `hello-plugin.hello-world` layout;
|
||||||
- availability of the workspace service from the `tooling` runtime capability;
|
- availability of the workspace service from the `tooling` runtime capability;
|
||||||
|
- best-effort workspace watch setup, including a non-fatal log when unavailable;
|
||||||
- the first layout render, including project/node identifiers.
|
- the first layout render, including project/node identifiers.
|
||||||
|
|
||||||
|
During command invocation the plugin logs and returns structured feedback for
|
||||||
|
programmatic callers. The current human menu-click UI does not guarantee display
|
||||||
|
of that return value.
|
||||||
|
|
||||||
|
- skipped command feedback when no project or no `helloPlugin.ownerAgentId` is available;
|
||||||
|
- launched background command feedback when `helloPlugin.ownerAgentId` is configured;
|
||||||
|
|
||||||
These messages are intentionally small and stable so installation, bundle import, activation and
|
These messages are intentionally small and stable so installation, bundle import, activation and
|
||||||
layout rendering failures can be separated quickly in IdeA logs/devtools.
|
layout rendering failures can be separated quickly in IdeA logs/devtools.
|
||||||
|
|||||||
@ -1,6 +1,19 @@
|
|||||||
import type { ActivateContext } from "@idea/plugin-sdk";
|
import type { ActivateContext, CommandTaskStatus } from "@idea/plugin-sdk";
|
||||||
import { STORAGE_KEYS } from "../constants.js";
|
import { STORAGE_KEYS } from "../constants.js";
|
||||||
|
|
||||||
|
export type HelloCommandFeedback =
|
||||||
|
| {
|
||||||
|
status: "skipped";
|
||||||
|
reason: "services-unavailable" | "no-focused-project" | "missing-owner-agent";
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
status: "launched";
|
||||||
|
taskId: string;
|
||||||
|
state: CommandTaskStatus["state"];
|
||||||
|
message: string;
|
||||||
|
};
|
||||||
|
|
||||||
export async function useWorkspaceSdk(ctx: ActivateContext): Promise<void> {
|
export async function useWorkspaceSdk(ctx: ActivateContext): Promise<void> {
|
||||||
const workspace = ctx.services?.workspace;
|
const workspace = ctx.services?.workspace;
|
||||||
if (!workspace) return;
|
if (!workspace) return;
|
||||||
@ -44,14 +57,18 @@ export async function useWorkspaceSdk(ctx: ActivateContext): Promise<void> {
|
|||||||
messages: diagnostic?.messages
|
messages: diagnostic?.messages
|
||||||
});
|
});
|
||||||
|
|
||||||
const watch = await workspace.watch(".ideai", (event) => {
|
try {
|
||||||
ctx.logger.info("workspace watch event", {
|
const watch = await workspace.watch(".ideai", (event) => {
|
||||||
path: event.path,
|
ctx.logger.info("workspace watch event", {
|
||||||
kind: event.kind,
|
path: event.path,
|
||||||
operation: event.operation
|
kind: event.kind,
|
||||||
});
|
operation: event.operation
|
||||||
}, project.id);
|
});
|
||||||
ctx.subscriptions.push(watch);
|
}, project.id);
|
||||||
|
ctx.subscriptions.push(watch);
|
||||||
|
} catch (error) {
|
||||||
|
ctx.logger.info("workspace watch unavailable", { error });
|
||||||
|
}
|
||||||
|
|
||||||
const events = await ctx.services?.events.subscribe(
|
const events = await ctx.services?.events.subscribe(
|
||||||
{
|
{
|
||||||
@ -70,14 +87,42 @@ export async function useWorkspaceSdk(ctx: ActivateContext): Promise<void> {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
if (events) ctx.subscriptions.push(events);
|
if (events) ctx.subscriptions.push(events);
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function runHelloCommandTask(ctx: ActivateContext): Promise<HelloCommandFeedback> {
|
||||||
|
if (!ctx.services) {
|
||||||
|
const feedback = {
|
||||||
|
status: "skipped",
|
||||||
|
reason: "services-unavailable",
|
||||||
|
message: "The tooling service facade is unavailable for hello-plugin."
|
||||||
|
} as const;
|
||||||
|
ctx.logger.info("hello command skipped", feedback);
|
||||||
|
return feedback;
|
||||||
|
}
|
||||||
|
|
||||||
|
const project = await ctx.services.workspace.getCurrentProject();
|
||||||
|
if (!project) {
|
||||||
|
const feedback = {
|
||||||
|
status: "skipped",
|
||||||
|
reason: "no-focused-project",
|
||||||
|
message: "Open a project before launching the hello-plugin task."
|
||||||
|
} as const;
|
||||||
|
ctx.logger.info("hello command skipped", feedback);
|
||||||
|
return feedback;
|
||||||
|
}
|
||||||
|
|
||||||
const ownerAgentId = await ctx.storage?.get<string>(STORAGE_KEYS.ownerAgentId);
|
const ownerAgentId = await ctx.storage?.get<string>(STORAGE_KEYS.ownerAgentId);
|
||||||
if (!ownerAgentId) {
|
if (!ownerAgentId) {
|
||||||
ctx.logger.info("command task example skipped: no owner agent configured");
|
const feedback = {
|
||||||
return;
|
status: "skipped",
|
||||||
|
reason: "missing-owner-agent",
|
||||||
|
message: "Configure helloPlugin.ownerAgentId in plugin storage before launching the task."
|
||||||
|
} as const;
|
||||||
|
ctx.logger.info("hello command skipped", feedback);
|
||||||
|
return feedback;
|
||||||
}
|
}
|
||||||
|
|
||||||
const task = await ctx.services?.tasks.runCommand({
|
const task = await ctx.services.tasks.runCommand({
|
||||||
projectId: project.id,
|
projectId: project.id,
|
||||||
ownerAgentId,
|
ownerAgentId,
|
||||||
label: "Hello plugin command",
|
label: "Hello plugin command",
|
||||||
@ -87,12 +132,17 @@ export async function useWorkspaceSdk(ctx: ActivateContext): Promise<void> {
|
|||||||
recordOnly: true
|
recordOnly: true
|
||||||
});
|
});
|
||||||
|
|
||||||
if (task) {
|
const status = await ctx.services.tasks.getCommandStatus(task.taskId);
|
||||||
const status = await ctx.services?.tasks.getCommandStatus(task.taskId);
|
const feedback = {
|
||||||
ctx.logger.info("command task launched", {
|
status: "launched",
|
||||||
taskId: task.taskId,
|
taskId: task.taskId,
|
||||||
state: status?.state ?? task.state,
|
state: status?.state ?? task.state,
|
||||||
exitCode: status?.exitCode ?? task.exitCode
|
message: "Started the hello-plugin background command."
|
||||||
});
|
} as const;
|
||||||
}
|
|
||||||
|
ctx.logger.info("hello command task launched", {
|
||||||
|
...feedback,
|
||||||
|
exitCode: status?.exitCode ?? task.exitCode
|
||||||
|
});
|
||||||
|
return feedback;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import type { ActivateContext, IdeAPluginModule } from "@idea/plugin-sdk";
|
|||||||
import { COMMAND_ID, LAYOUT_TYPE } from "./constants.js";
|
import { COMMAND_ID, LAYOUT_TYPE } from "./constants.js";
|
||||||
import { HelloWorldLayout } from "./core/layout.js";
|
import { HelloWorldLayout } from "./core/layout.js";
|
||||||
import { initializePluginStorage, recordCommandRun } from "./core/storage.js";
|
import { initializePluginStorage, recordCommandRun } from "./core/storage.js";
|
||||||
import { useWorkspaceSdk } from "./core/workspace.js";
|
import { runHelloCommandTask, useWorkspaceSdk } from "./core/workspace.js";
|
||||||
|
|
||||||
export function activate(ctx: ActivateContext): void {
|
export function activate(ctx: ActivateContext): void {
|
||||||
ctx.logger.info("activating hello-plugin", {
|
ctx.logger.info("activating hello-plugin", {
|
||||||
@ -14,8 +14,9 @@ export function activate(ctx: ActivateContext): void {
|
|||||||
|
|
||||||
const commandDisposable = ctx.commands?.registerCommand(COMMAND_ID, async () => {
|
const commandDisposable = ctx.commands?.registerCommand(COMMAND_ID, async () => {
|
||||||
const commandRunCount = await recordCommandRun(ctx);
|
const commandRunCount = await recordCommandRun(ctx);
|
||||||
ctx.logger.info("command executed", { commandId: COMMAND_ID, commandRunCount });
|
const feedback = await runHelloCommandTask(ctx);
|
||||||
return "hello-world";
|
ctx.logger.info("command executed", { commandId: COMMAND_ID, commandRunCount, feedback });
|
||||||
|
return feedback;
|
||||||
});
|
});
|
||||||
|
|
||||||
if (commandDisposable) {
|
if (commandDisposable) {
|
||||||
|
|||||||
@ -13,6 +13,7 @@
|
|||||||
},
|
},
|
||||||
"files": [
|
"files": [
|
||||||
"dist",
|
"dist",
|
||||||
|
"docs",
|
||||||
"README.md"
|
"README.md"
|
||||||
],
|
],
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
@ -128,6 +128,7 @@ export interface WorkspaceService {
|
|||||||
/**
|
/**
|
||||||
* Extension point for host file watching. The MVP SDK reserves the public
|
* Extension point for host file watching. The MVP SDK reserves the public
|
||||||
* shape; hosts may reject with a clear not-implemented error until #127 lands.
|
* shape; hosts may reject with a clear not-implemented error until #127 lands.
|
||||||
|
* Plugins must treat watch setup as best-effort and non-fatal.
|
||||||
*/
|
*/
|
||||||
watch(path: string, handler: WorkspaceWatchHandler, projectId?: string): Promise<WorkspaceWatch>;
|
watch(path: string, handler: WorkspaceWatchHandler, projectId?: string): Promise<WorkspaceWatch>;
|
||||||
/** Queries a bounded, generic project structure read model. */
|
/** Queries a bounded, generic project structure read model. */
|
||||||
@ -219,9 +220,19 @@ export interface ProjectStructure {
|
|||||||
|
|
||||||
export interface BackgroundTaskStatus {
|
export interface BackgroundTaskStatus {
|
||||||
taskId: string;
|
taskId: string;
|
||||||
|
/**
|
||||||
|
* Agent that owns completion delivery and Work attribution for this task.
|
||||||
|
* This is host-assigned for existing tasks and should be treated as an opaque
|
||||||
|
* agent id by plugins.
|
||||||
|
*/
|
||||||
ownerAgentId: string;
|
ownerAgentId: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
kind: string;
|
kind: string;
|
||||||
|
/**
|
||||||
|
* Work read-model status. A skipped plugin command is not a background task
|
||||||
|
* and therefore never appears here; skipped commands should be reported by
|
||||||
|
* the command handler return value and plugin logs.
|
||||||
|
*/
|
||||||
status: "pending" | "running" | "completed" | "failed" | "cancelled" | "delivered";
|
status: "pending" | "running" | "completed" | "failed" | "cancelled" | "delivered";
|
||||||
exitCode: number | null;
|
exitCode: number | null;
|
||||||
summary: string | null;
|
summary: string | null;
|
||||||
@ -245,7 +256,11 @@ export interface BackgroundTaskRetryResult {
|
|||||||
export interface RunCommandTaskOptions {
|
export interface RunCommandTaskOptions {
|
||||||
/** Project that owns the command workspace. Defaults to the focused project. */
|
/** Project that owns the command workspace. Defaults to the focused project. */
|
||||||
projectId?: string;
|
projectId?: string;
|
||||||
/** Agent id used by IdeA Work for ownership, cancellation and completion delivery. */
|
/**
|
||||||
|
* Real agent id used by IdeA Work for ownership, cancellation and completion
|
||||||
|
* delivery. Plugins must obtain this from host/plugin state for the workflow
|
||||||
|
* they are serving; placeholder ids are only acceptable in isolated examples.
|
||||||
|
*/
|
||||||
ownerAgentId: string;
|
ownerAgentId: string;
|
||||||
/** Human-facing label shown in Work. Defaults to the command line. */
|
/** Human-facing label shown in Work. Defaults to the command line. */
|
||||||
label?: string;
|
label?: string;
|
||||||
@ -257,7 +272,12 @@ export interface RunCommandTaskOptions {
|
|||||||
cwd?: string;
|
cwd?: string;
|
||||||
/** Extra environment variables for the command. */
|
/** Extra environment variables for the command. */
|
||||||
env?: Record<string, string> | Array<[string, string]>;
|
env?: Record<string, string> | Array<[string, string]>;
|
||||||
/** When true, completion is recorded without waking the owner agent. */
|
/**
|
||||||
|
* When true, completion is recorded without waking the owner agent. This does
|
||||||
|
* not hide the task from Work/background-task surfaces and does not represent
|
||||||
|
* a skipped command. If preconditions fail, return readable command feedback
|
||||||
|
* instead of launching a record-only task.
|
||||||
|
*/
|
||||||
recordOnly?: boolean;
|
recordOnly?: boolean;
|
||||||
/** Optional absolute deadline, epoch milliseconds. */
|
/** Optional absolute deadline, epoch milliseconds. */
|
||||||
deadlineMs?: number;
|
deadlineMs?: number;
|
||||||
@ -265,9 +285,17 @@ export interface RunCommandTaskOptions {
|
|||||||
|
|
||||||
export interface CommandTaskStatus {
|
export interface CommandTaskStatus {
|
||||||
taskId: string;
|
taskId: string;
|
||||||
|
/**
|
||||||
|
* Agent that owns this command task. The host uses it for correlation,
|
||||||
|
* cancellation and completion delivery.
|
||||||
|
*/
|
||||||
ownerAgentId: string;
|
ownerAgentId: string;
|
||||||
projectId: string;
|
projectId: string;
|
||||||
kind: string;
|
kind: string;
|
||||||
|
/**
|
||||||
|
* Lifecycle state of a command task that was actually launched. There is no
|
||||||
|
* `skipped` state: skipped commands are command-handler feedback, not tasks.
|
||||||
|
*/
|
||||||
state: "queued" | "running" | "waiting" | "completed" | "failed" | "cancelled" | "expired";
|
state: "queued" | "running" | "waiting" | "completed" | "failed" | "cancelled" | "expired";
|
||||||
exitCode: number | null;
|
exitCode: number | null;
|
||||||
summary: string | null;
|
summary: string | null;
|
||||||
@ -479,7 +507,15 @@ export interface ConfigDocumentService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface BackgroundTaskService {
|
export interface BackgroundTaskService {
|
||||||
/** Launches a non-interactive command as a first-class IdeA background task. */
|
/**
|
||||||
|
* Launches a non-interactive command as a first-class IdeA background task.
|
||||||
|
*
|
||||||
|
* Call this only after command preconditions are satisfied. The returned
|
||||||
|
* `CommandTaskStatus` means a task exists and can be inspected through command
|
||||||
|
* status APIs and Work/background-task surfaces. A plugin command that decides
|
||||||
|
* not to launch work should return readable command feedback, for example
|
||||||
|
* `{ status: "skipped", reason, message }`, and should not call `runCommand()`.
|
||||||
|
*/
|
||||||
runCommand(options: RunCommandTaskOptions): Promise<CommandTaskStatus>;
|
runCommand(options: RunCommandTaskOptions): Promise<CommandTaskStatus>;
|
||||||
/** Reads one command task directly from the host task store. */
|
/** Reads one command task directly from the host task store. */
|
||||||
getCommandStatus(taskId: string): Promise<CommandTaskStatus | null>;
|
getCommandStatus(taskId: string): Promise<CommandTaskStatus | null>;
|
||||||
|
|||||||
Reference in New Issue
Block a user