Make workspace, agent, and schedule automation consistent (#2186)

* feat(workspaces): align agent and schedule automation

Make workspace identity the shared placement boundary for MCP and CLI, while caller identity determines parentage. Keep heartbeats minimal and cron-based without changing legacy rolling interval semantics.

* test(cli): expect canonical schedule cadence

* fix(automation): preserve workspace and schedule compatibility

* fix(automation): preserve compatibility edges

* fix(workspaces): align MCP lifecycle resolution

* fix(workspaces): preserve creation intent

* fix(workspaces): preserve branch and schedule identity
This commit is contained in:
Mohamed Boudra
2026-07-18 14:04:48 +02:00
committed by GitHub
parent 98f6611362
commit ffe76a7e57
66 changed files with 2791 additions and 924 deletions
+9 -8
View File
@@ -53,7 +53,8 @@ try {
const result = await $`npx paseo run --help`.nothrow();
assert.strictEqual(result.exitCode, 0, "run --help should exit 0");
assert(result.stdout.includes("-d"), "help should mention -d flag");
assert(result.stdout.includes("--detach"), "help should mention --detach flag");
assert(result.stdout.includes("--background"), "help should mention --background flag");
assert(!result.stdout.includes("--detach"), "help should hide legacy --detach syntax");
assert(result.stdout.includes("--title"), "help should mention --title option");
assert(result.stdout.includes("--provider"), "help should mention --provider option");
assert(result.stdout.includes("--mode"), "help should mention --mode option");
@@ -174,18 +175,18 @@ try {
console.log("✓ run --output-schema flag is accepted\n");
}
// Test 10: run --output-schema cannot be used with --detach
// Test 10: run --output-schema cannot be used with --background
{
console.log("Test 10: run --output-schema cannot be used with --detach");
console.log("Test 10: run --output-schema cannot be used with --background");
const result =
await $`PASEO_HOST=localhost:${port} PASEO_HOME=${paseoHome} npx paseo run -d --output-schema ${schemaPath} "test prompt"`.nothrow();
assert.notStrictEqual(result.exitCode, 0, "should fail with --detach and --output-schema");
await $`PASEO_HOST=localhost:${port} PASEO_HOME=${paseoHome} npx paseo run --background --output-schema ${schemaPath} "test prompt"`.nothrow();
assert.notStrictEqual(result.exitCode, 0, "should fail with --background and --output-schema");
const output = result.stdout + result.stderr;
assert(
output.includes("--output-schema cannot be used with --detach"),
"error should explain detach incompatibility",
output.includes("--output-schema cannot be used with --background"),
"error should explain background incompatibility",
);
console.log("✓ run --output-schema cannot be used with --detach\n");
console.log("✓ run --output-schema cannot be used with --background\n");
}
// Test 11: -q (quiet) flag is accepted with run
+4 -4
View File
@@ -153,13 +153,13 @@ try {
console.log("✓ --json flag is accepted with worktree ls\n");
}
// Test 11: paseo --help shows worktree subcommand
// Test 11: paseo --help keeps the compatibility command hidden
{
console.log("Test 11: paseo --help shows worktree subcommand");
console.log("Test 11: paseo --help hides worktree compatibility command");
const result = await $`npx paseo --help`.nothrow();
assert.strictEqual(result.exitCode, 0, "paseo --help should exit 0");
assert(result.stdout.includes("worktree"), "help should mention worktree subcommand");
console.log("✓ paseo --help shows worktree subcommand\n");
assert(!result.stdout.includes("worktree"), "help should not advertise worktree subcommand");
console.log("✓ paseo --help hides worktree compatibility command\n");
}
} finally {
// Clean up temp directory
+26 -1
View File
@@ -53,7 +53,7 @@ try {
assert.strictEqual(created.exitCode, 0, created.stderr);
const createdJson = JSON.parse(created.stdout);
assert.strictEqual(createdJson.name, "review-prs");
assert.strictEqual(createdJson.cadence, "every:5m");
assert.strictEqual(createdJson.cadence, "cron:*/5 * * * *");
assert(
typeof createdJson.target === "string" &&
(createdJson.target.startsWith("agent:") || createdJson.target === "new-agent:claude"),
@@ -144,6 +144,31 @@ try {
console.log("schedule rejects provider with self target\n");
}
{
console.log("Test 1d: compatibility agent-target schedules remain deletable");
const created = await ctx.paseo(
[
"schedule",
"create",
"Legacy heartbeat",
"--cron",
"0 0 1 1 *",
"--target",
"00000000-0000-4000-8000-000000000001",
"--json",
],
{ timeout: 30000 },
);
assert.strictEqual(created.exitCode, 0, created.stderr);
const createdJson = JSON.parse(created.stdout);
assert.strictEqual(createdJson.target, "agent:0000000");
const deleted = await ctx.paseo(["schedule", "delete", createdJson.id, "--json"]);
assert.strictEqual(deleted.exitCode, 0, deleted.stderr);
assert.strictEqual(JSON.parse(deleted.stdout).id, createdJson.id);
console.log("compatibility agent-target schedules remain deletable\n");
}
{
console.log("Test 2: loop run/ls/inspect/logs/stop work");
const run = await ctx.paseo(