docs(sdk): fige le contrat command-and-feedback et aligne l'exemple hello-plugin
Documente la règle publique menu -> command handler -> tâche de fond optionnelle -> feedback (docs/commands-and-feedback.md + README), clarifie via JSDoc les invariants de runCommand/recordOnly/ownerAgentId dans runtime.ts, et met à jour l'exemple hello-plugin (feedback structuré launched/skipped, watch non-fatal) pour qu'il illustre fidèlement le contrat documenté. Publie docs/ dans le package npm. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@ -6,7 +6,10 @@ It exercises the current plugin primitives end to end:
|
||||
|
||||
- top-level menu: `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`.
|
||||
- plugin-owned storage: activation count, command run count and initialization flag;
|
||||
- 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.hello-world` layout;
|
||||
- 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.
|
||||
|
||||
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
|
||||
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";
|
||||
|
||||
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> {
|
||||
const workspace = ctx.services?.workspace;
|
||||
if (!workspace) return;
|
||||
@ -44,14 +57,18 @@ export async function useWorkspaceSdk(ctx: ActivateContext): Promise<void> {
|
||||
messages: diagnostic?.messages
|
||||
});
|
||||
|
||||
const watch = await workspace.watch(".ideai", (event) => {
|
||||
ctx.logger.info("workspace watch event", {
|
||||
path: event.path,
|
||||
kind: event.kind,
|
||||
operation: event.operation
|
||||
});
|
||||
}, project.id);
|
||||
ctx.subscriptions.push(watch);
|
||||
try {
|
||||
const watch = await workspace.watch(".ideai", (event) => {
|
||||
ctx.logger.info("workspace watch event", {
|
||||
path: event.path,
|
||||
kind: event.kind,
|
||||
operation: event.operation
|
||||
});
|
||||
}, project.id);
|
||||
ctx.subscriptions.push(watch);
|
||||
} catch (error) {
|
||||
ctx.logger.info("workspace watch unavailable", { error });
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
if (!ownerAgentId) {
|
||||
ctx.logger.info("command task example skipped: no owner agent configured");
|
||||
return;
|
||||
const feedback = {
|
||||
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,
|
||||
ownerAgentId,
|
||||
label: "Hello plugin command",
|
||||
@ -87,12 +132,17 @@ export async function useWorkspaceSdk(ctx: ActivateContext): Promise<void> {
|
||||
recordOnly: true
|
||||
});
|
||||
|
||||
if (task) {
|
||||
const status = await ctx.services?.tasks.getCommandStatus(task.taskId);
|
||||
ctx.logger.info("command task launched", {
|
||||
taskId: task.taskId,
|
||||
state: status?.state ?? task.state,
|
||||
exitCode: status?.exitCode ?? task.exitCode
|
||||
});
|
||||
}
|
||||
const status = await ctx.services.tasks.getCommandStatus(task.taskId);
|
||||
const feedback = {
|
||||
status: "launched",
|
||||
taskId: task.taskId,
|
||||
state: status?.state ?? task.state,
|
||||
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 { HelloWorldLayout } from "./core/layout.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 {
|
||||
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 commandRunCount = await recordCommandRun(ctx);
|
||||
ctx.logger.info("command executed", { commandId: COMMAND_ID, commandRunCount });
|
||||
return "hello-world";
|
||||
const feedback = await runHelloCommandTask(ctx);
|
||||
ctx.logger.info("command executed", { commandId: COMMAND_ID, commandRunCount, feedback });
|
||||
return feedback;
|
||||
});
|
||||
|
||||
if (commandDisposable) {
|
||||
|
||||
Reference in New Issue
Block a user