overlane 0.1.112 → 0.1.114
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/dist/overlane.mjs +371 -67
- package/package.json +1 -1
- package/plugins/claude/plugins/mvrx-harness/.claude-plugin/plugin.json +1 -1
- package/plugins/claude/plugins/mvrx-harness/hooks/hooks.json +24 -1
- package/plugins/claude/plugins/mvrx-harness/scripts/harness-context.mjs +29 -29
- package/plugins/claude/plugins/mvrx-harness/scripts/harness-guard.mjs +63 -0
- package/plugins/claude/plugins/mvrx-harness/scripts/harness-intake.mjs +71 -0
- package/plugins/claude/plugins/mvrx-harness/scripts/harness-quota.mjs +23 -23
- package/plugins/claude/plugins/mvrx-harness/scripts/harness-statusline.mjs +29 -29
- package/plugins/claude/plugins/mvrx-harness/scripts/harness-stop.mjs +23 -23
- package/plugins/codex/plugins/mvrx-harness/.codex-plugin/plugin.json +1 -1
- package/plugins/codex/plugins/mvrx-harness/hooks/hooks.json +24 -1
- package/plugins/codex/plugins/mvrx-harness/scripts/harness-context.mjs +29 -29
- package/plugins/codex/plugins/mvrx-harness/scripts/harness-guard.mjs +63 -0
- package/plugins/codex/plugins/mvrx-harness/scripts/harness-intake.mjs +71 -0
- package/plugins/codex/plugins/mvrx-harness/scripts/harness-quota.mjs +23 -23
- package/plugins/codex/plugins/mvrx-harness/scripts/harness-statusline.mjs +29 -29
- package/plugins/codex/plugins/mvrx-harness/scripts/harness-stop.mjs +23 -23
- package/plugins/release-manifest.json +69 -18
package/dist/overlane.mjs
CHANGED
|
@@ -21308,6 +21308,74 @@ var init_identity = __esm({
|
|
|
21308
21308
|
}
|
|
21309
21309
|
});
|
|
21310
21310
|
|
|
21311
|
+
// ../contracts/src/task-priority.ts
|
|
21312
|
+
var TASK_PRIORITIES, TaskPriority, TASK_ORIGINS, TaskOrigin, taskQueuePaths, RequestId2, PrioritiseRequest, PrioritiseResult, QueueEntry, TaskQueue, NextTask, TASK_ENFORCEMENT, TaskEnforcement, TaskPolicy, SetTaskPolicyRequest;
|
|
21313
|
+
var init_task_priority = __esm({
|
|
21314
|
+
"../contracts/src/task-priority.ts"() {
|
|
21315
|
+
"use strict";
|
|
21316
|
+
init_zod();
|
|
21317
|
+
init_common();
|
|
21318
|
+
init_executor();
|
|
21319
|
+
init_task_api();
|
|
21320
|
+
init_task_contract();
|
|
21321
|
+
TASK_PRIORITIES = ["P0", "P1", "P2", "P3"];
|
|
21322
|
+
TaskPriority = external_exports.enum(TASK_PRIORITIES);
|
|
21323
|
+
TASK_ORIGINS = ["user", "plan", "agent", "system"];
|
|
21324
|
+
TaskOrigin = external_exports.enum(TASK_ORIGINS);
|
|
21325
|
+
taskQueuePaths = {
|
|
21326
|
+
base: (tenantId, projectId) => `/v1/tenants/${encodeURIComponent(tenantId)}/projects/${encodeURIComponent(projectId)}/queue`,
|
|
21327
|
+
next: (tenantId, projectId) => `${taskQueuePaths.base(tenantId, projectId)}/next`,
|
|
21328
|
+
policy: (tenantId, projectId) => `${taskQueuePaths.base(tenantId, projectId)}/policy`,
|
|
21329
|
+
prioritise: (tenantId, projectId, taskId) => `${taskQueuePaths.base(tenantId, projectId)}/${encodeURIComponent(taskId)}/prioritise`
|
|
21330
|
+
};
|
|
21331
|
+
RequestId2 = external_exports.string().min(8).max(128);
|
|
21332
|
+
PrioritiseRequest = external_exports.object({
|
|
21333
|
+
requestId: RequestId2,
|
|
21334
|
+
priority: TaskPriority,
|
|
21335
|
+
top: external_exports.boolean().default(false),
|
|
21336
|
+
/** Who asked for the work; recorded the first time a task is ranked. */
|
|
21337
|
+
origin: TaskOrigin.default("agent"),
|
|
21338
|
+
reason: external_exports.string().min(1).max(300).optional(),
|
|
21339
|
+
/** The task this one displaces; the ledger records `task.preempted`. */
|
|
21340
|
+
preempts: TaskId.optional(),
|
|
21341
|
+
executor: Executor
|
|
21342
|
+
}).strict();
|
|
21343
|
+
PrioritiseResult = external_exports.object({
|
|
21344
|
+
taskId: TaskId,
|
|
21345
|
+
priority: TaskPriority,
|
|
21346
|
+
rank: external_exports.number().int(),
|
|
21347
|
+
origin: TaskOrigin,
|
|
21348
|
+
previous: external_exports.object({ priority: TaskPriority, rank: external_exports.number().int() }).strict().nullable(),
|
|
21349
|
+
changed: external_exports.boolean()
|
|
21350
|
+
}).strict();
|
|
21351
|
+
QueueEntry = external_exports.object({
|
|
21352
|
+
taskId: TaskId,
|
|
21353
|
+
title: external_exports.string(),
|
|
21354
|
+
state: TaskState,
|
|
21355
|
+
pauseReason: PauseReason.optional(),
|
|
21356
|
+
priority: TaskPriority,
|
|
21357
|
+
rank: external_exports.number().int(),
|
|
21358
|
+
origin: TaskOrigin,
|
|
21359
|
+
version: external_exports.number().int().positive()
|
|
21360
|
+
}).strict();
|
|
21361
|
+
TaskQueue = external_exports.object({ tasks: external_exports.array(QueueEntry) }).strict();
|
|
21362
|
+
NextTask = external_exports.object({
|
|
21363
|
+
task: QueueEntry.nullable(),
|
|
21364
|
+
preempt: external_exports.boolean(),
|
|
21365
|
+
why: external_exports.string()
|
|
21366
|
+
}).strict();
|
|
21367
|
+
TASK_ENFORCEMENT = ["required", "relaxed"];
|
|
21368
|
+
TaskEnforcement = external_exports.enum(TASK_ENFORCEMENT);
|
|
21369
|
+
TaskPolicy = external_exports.object({
|
|
21370
|
+
enforcement: TaskEnforcement,
|
|
21371
|
+
reason: external_exports.string().optional(),
|
|
21372
|
+
changedBy: external_exports.string().optional(),
|
|
21373
|
+
updatedAt: Timestamp.optional()
|
|
21374
|
+
}).strict();
|
|
21375
|
+
SetTaskPolicyRequest = external_exports.object({ requestId: RequestId2, enforcement: TaskEnforcement, reason: external_exports.string().min(1).max(300).optional(), executor: Executor }).strict().refine((request) => request.enforcement === "required" || request.reason !== void 0, { message: "relaxing the task requirement needs a reason", path: ["reason"] });
|
|
21376
|
+
}
|
|
21377
|
+
});
|
|
21378
|
+
|
|
21311
21379
|
// ../contracts/src/index.ts
|
|
21312
21380
|
var init_src = __esm({
|
|
21313
21381
|
"../contracts/src/index.ts"() {
|
|
@@ -21325,6 +21393,7 @@ var init_src = __esm({
|
|
|
21325
21393
|
init_release();
|
|
21326
21394
|
init_kit();
|
|
21327
21395
|
init_identity();
|
|
21396
|
+
init_task_priority();
|
|
21328
21397
|
}
|
|
21329
21398
|
});
|
|
21330
21399
|
|
|
@@ -28659,7 +28728,7 @@ var require_dist = __commonJS({
|
|
|
28659
28728
|
});
|
|
28660
28729
|
|
|
28661
28730
|
// src/assets.ts
|
|
28662
|
-
import { basename as basename3, join as
|
|
28731
|
+
import { basename as basename3, join as join22, resolve as resolve6 } from "node:path";
|
|
28663
28732
|
import { fileURLToPath } from "node:url";
|
|
28664
28733
|
function packageRoot(env = process.env) {
|
|
28665
28734
|
const override = env["MVRX_PACKAGE_ROOT"];
|
|
@@ -28668,16 +28737,16 @@ function packageRoot(env = process.env) {
|
|
|
28668
28737
|
}
|
|
28669
28738
|
function assetDir(env = process.env) {
|
|
28670
28739
|
const override = env["MVRX_ASSET_DIR"];
|
|
28671
|
-
return override !== void 0 && override !== "" ? override :
|
|
28740
|
+
return override !== void 0 && override !== "" ? override : join22(packageRoot(env), "assets");
|
|
28672
28741
|
}
|
|
28673
28742
|
function assetFile(name2) {
|
|
28674
|
-
return
|
|
28743
|
+
return join22(assetDir(), basename3(name2));
|
|
28675
28744
|
}
|
|
28676
28745
|
var VERSION;
|
|
28677
28746
|
var init_assets = __esm({
|
|
28678
28747
|
"src/assets.ts"() {
|
|
28679
28748
|
"use strict";
|
|
28680
|
-
VERSION = true ? "0.1.
|
|
28749
|
+
VERSION = true ? "0.1.114" : "0.0.0-dev";
|
|
28681
28750
|
}
|
|
28682
28751
|
});
|
|
28683
28752
|
|
|
@@ -36606,7 +36675,7 @@ var init_treesitter = __esm({
|
|
|
36606
36675
|
import { execFile } from "node:child_process";
|
|
36607
36676
|
import { createHash as createHash6 } from "node:crypto";
|
|
36608
36677
|
import { lstat, readFile as readFile4 } from "node:fs/promises";
|
|
36609
|
-
import { join as
|
|
36678
|
+
import { join as join23 } from "node:path";
|
|
36610
36679
|
import { promisify } from "node:util";
|
|
36611
36680
|
function shardKeyOf(shard) {
|
|
36612
36681
|
return `sha256:${sha256Hex(Buffer.from(`${shard.path}\0${shard.contentHash}\0${shard.precision}`, "utf8"))}`;
|
|
@@ -36633,7 +36702,7 @@ async function mapLimit(items, limit, task) {
|
|
|
36633
36702
|
return results;
|
|
36634
36703
|
}
|
|
36635
36704
|
async function hashRegularFile(repoRoot, path) {
|
|
36636
|
-
const absolute =
|
|
36705
|
+
const absolute = join23(repoRoot, path);
|
|
36637
36706
|
try {
|
|
36638
36707
|
const stats = await lstat(absolute);
|
|
36639
36708
|
if (!stats.isFile()) return null;
|
|
@@ -36671,7 +36740,7 @@ async function buildSnapshot(options) {
|
|
|
36671
36740
|
const needParse = [...hashes.keys()].filter((path) => !byPath.has(path));
|
|
36672
36741
|
const parsed = await mapLimit(needParse, 8, async (path) => {
|
|
36673
36742
|
if (languageForPath(path) === null) return { path, shard: null };
|
|
36674
|
-
const bytes = await readFile4(
|
|
36743
|
+
const bytes = await readFile4(join23(options.repoRoot, path));
|
|
36675
36744
|
if (bytes.byteLength > MAX_PARSE_BYTES) return { path, shard: null };
|
|
36676
36745
|
const hash2 = `sha256:${sha256Hex(bytes)}`;
|
|
36677
36746
|
if (hash2 !== hashes.get(path)) throw new Error(`${path} changed while the snapshot was being built`);
|
|
@@ -36814,7 +36883,7 @@ var init_oidc = __esm({
|
|
|
36814
36883
|
// ../index-builder/src/run.ts
|
|
36815
36884
|
import { execFile as execFile2 } from "node:child_process";
|
|
36816
36885
|
import { mkdir as mkdir3, readdir as readdir4, rm as rm2, writeFile as writeFile3 } from "node:fs/promises";
|
|
36817
|
-
import { join as
|
|
36886
|
+
import { join as join24, resolve as resolve7 } from "node:path";
|
|
36818
36887
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
36819
36888
|
import { promisify as promisify2 } from "node:util";
|
|
36820
36889
|
async function git3(root, args2) {
|
|
@@ -36886,13 +36955,13 @@ ${USAGE}`);
|
|
|
36886
36955
|
}
|
|
36887
36956
|
}
|
|
36888
36957
|
async function writeSnapshot(dir, built) {
|
|
36889
|
-
await mkdir3(
|
|
36890
|
-
for (const name2 of await readdir4(
|
|
36891
|
-
await writeFile3(
|
|
36892
|
-
await writeFile3(
|
|
36958
|
+
await mkdir3(join24(dir, "shards"), { recursive: true });
|
|
36959
|
+
for (const name2 of await readdir4(join24(dir, "shards"))) await rm2(join24(dir, "shards", name2));
|
|
36960
|
+
await writeFile3(join24(dir, "manifest.json"), JSON.stringify(built.manifest, null, 2));
|
|
36961
|
+
await writeFile3(join24(dir, "uncovered.json"), JSON.stringify(built.uncovered, null, 2));
|
|
36893
36962
|
for (const shard of built.shards) {
|
|
36894
36963
|
const name2 = shardKeyOf(shard).slice("sha256:".length);
|
|
36895
|
-
await writeFile3(
|
|
36964
|
+
await writeFile3(join24(dir, "shards", `${name2}.json`), JSON.stringify(shard));
|
|
36896
36965
|
}
|
|
36897
36966
|
}
|
|
36898
36967
|
var execFileAsync2, USAGE, UsageError2, OPTIONS;
|
|
@@ -51730,7 +51799,7 @@ var init_cloud = __esm({
|
|
|
51730
51799
|
// ../code-shim/src/git.ts
|
|
51731
51800
|
import { execFileSync } from "node:child_process";
|
|
51732
51801
|
import { existsSync as existsSync6 } from "node:fs";
|
|
51733
|
-
import { join as
|
|
51802
|
+
import { join as join28 } from "node:path";
|
|
51734
51803
|
function git4(root, args2) {
|
|
51735
51804
|
try {
|
|
51736
51805
|
return execFileSync("git", args2, { cwd: root, encoding: "utf8", stdio: ["ignore", "pipe", "ignore"], maxBuffer: 64 * 1024 * 1024, timeout: 1e4 });
|
|
@@ -51792,7 +51861,7 @@ function readWorkingCopyState(root) {
|
|
|
51792
51861
|
const head = headCommit2(root);
|
|
51793
51862
|
const raw = git4(root, ["status", "--porcelain=v2", "-z", "--untracked-files=all"]);
|
|
51794
51863
|
if (raw === null) return { head, dirty: /* @__PURE__ */ new Set(), deleted: /* @__PURE__ */ new Set(), renamed: /* @__PURE__ */ new Map() };
|
|
51795
|
-
return { head, ...parseStatus(raw, (path) => existsSync6(
|
|
51864
|
+
return { head, ...parseStatus(raw, (path) => existsSync6(join28(root, path))) };
|
|
51796
51865
|
}
|
|
51797
51866
|
var init_git = __esm({
|
|
51798
51867
|
"../code-shim/src/git.ts"() {
|
|
@@ -51803,16 +51872,16 @@ var init_git = __esm({
|
|
|
51803
51872
|
// ../code-shim/src/config.ts
|
|
51804
51873
|
import { readFileSync as readFileSync7 } from "node:fs";
|
|
51805
51874
|
import { homedir as homedir2 } from "node:os";
|
|
51806
|
-
import { join as
|
|
51875
|
+
import { join as join29 } from "node:path";
|
|
51807
51876
|
function configDir(env) {
|
|
51808
|
-
const base2 = env["XDG_CONFIG_HOME"] ?? (process.platform === "win32" ? env["APPDATA"] : void 0) ??
|
|
51809
|
-
return
|
|
51877
|
+
const base2 = env["XDG_CONFIG_HOME"] ?? (process.platform === "win32" ? env["APPDATA"] : void 0) ?? join29(homedir2(), ".config");
|
|
51878
|
+
return join29(base2, "mvrx-harness");
|
|
51810
51879
|
}
|
|
51811
51880
|
function findToken2(env, serviceUrl, now) {
|
|
51812
51881
|
const fromEnv = env["HARNESS_TOKEN"];
|
|
51813
51882
|
if (fromEnv !== void 0 && fromEnv.length > 0) return fromEnv;
|
|
51814
51883
|
try {
|
|
51815
|
-
const file2 = JSON.parse(readFileSync7(
|
|
51884
|
+
const file2 = JSON.parse(readFileSync7(join29(configDir(env), "credentials.json"), "utf8"));
|
|
51816
51885
|
const stored = file2[serviceUrl];
|
|
51817
51886
|
if (stored === void 0 || typeof stored.accessToken !== "string" || stored.accessToken.length === 0) return null;
|
|
51818
51887
|
if (typeof stored.expiresAt === "number" && stored.expiresAt <= now) return null;
|
|
@@ -51824,7 +51893,7 @@ function findToken2(env, serviceUrl, now) {
|
|
|
51824
51893
|
function resolveCloudConfig(root, env, now) {
|
|
51825
51894
|
let binding;
|
|
51826
51895
|
try {
|
|
51827
|
-
const parsed = ProjectBinding.safeParse(JSON.parse(readFileSync7(
|
|
51896
|
+
const parsed = ProjectBinding.safeParse(JSON.parse(readFileSync7(join29(root, ".harness", "project.json"), "utf8")));
|
|
51828
51897
|
if (!parsed.success) return null;
|
|
51829
51898
|
binding = parsed.data;
|
|
51830
51899
|
} catch {
|
|
@@ -52215,7 +52284,7 @@ var init_nav = __esm({
|
|
|
52215
52284
|
|
|
52216
52285
|
// ../code-shim/src/edit.ts
|
|
52217
52286
|
import { createHash as createHash8 } from "node:crypto";
|
|
52218
|
-
import { readFileSync as readFileSync9, writeFileSync as
|
|
52287
|
+
import { readFileSync as readFileSync9, writeFileSync as writeFileSync8 } from "node:fs";
|
|
52219
52288
|
function lineStarts(text) {
|
|
52220
52289
|
const starts = [0];
|
|
52221
52290
|
for (let i2 = 0; i2 < text.length; i2 += 1) if (text[i2] === "\n") starts.push(i2 + 1);
|
|
@@ -52284,7 +52353,7 @@ ${args2.content.replace(/\n+$/, "")}`;
|
|
|
52284
52353
|
const before = positionAt(next, changedStart);
|
|
52285
52354
|
const after = positionAt(next, insertAt + inserted.length);
|
|
52286
52355
|
const bytes = Buffer.from(next, "utf8");
|
|
52287
|
-
|
|
52356
|
+
writeFileSync8(absolute, bytes);
|
|
52288
52357
|
return {
|
|
52289
52358
|
ok: true,
|
|
52290
52359
|
path: args2.path,
|
|
@@ -52345,7 +52414,7 @@ async function renameSymbol(deps, args2) {
|
|
|
52345
52414
|
let next = item.text;
|
|
52346
52415
|
for (const offset of offsets) next = next.slice(0, offset) + args2.new_name + next.slice(offset + oldName.length);
|
|
52347
52416
|
const bytes = Buffer.from(next, "utf8");
|
|
52348
|
-
|
|
52417
|
+
writeFileSync8(item.absolute, bytes);
|
|
52349
52418
|
filesChanged.push({ path: item.path, edits: offsets.length, sha256: sha2563(bytes) });
|
|
52350
52419
|
edits += offsets.length;
|
|
52351
52420
|
}
|
|
@@ -58229,6 +58298,239 @@ var runResumeCommand = defineCommand({
|
|
|
58229
58298
|
});
|
|
58230
58299
|
var runCommands = [runStartCommand, runNextCommand, runClaimCommand, runDecideCommand, runEndCommand, runStatusCommand, runPauseCommand, runResumeCommand];
|
|
58231
58300
|
|
|
58301
|
+
// ../cli/src/task/queue.ts
|
|
58302
|
+
init_src();
|
|
58303
|
+
init_zod();
|
|
58304
|
+
import { randomUUID as randomUUID4 } from "node:crypto";
|
|
58305
|
+
import { mkdirSync as mkdirSync7, renameSync as renameSync5, writeFileSync as writeFileSync6 } from "node:fs";
|
|
58306
|
+
import { dirname as dirname7, join as join21 } from "node:path";
|
|
58307
|
+
var TASK_POLICY_PATH = join21(".harness", "task-policy.json");
|
|
58308
|
+
function writePolicyFile(root, policy, nowMs) {
|
|
58309
|
+
const path = join21(root, TASK_POLICY_PATH);
|
|
58310
|
+
mkdirSync7(dirname7(path), { recursive: true });
|
|
58311
|
+
const temp = `${path}.${process.pid}.tmp`;
|
|
58312
|
+
writeFileSync6(temp, `${JSON.stringify({ enforcement: policy.enforcement, ...policy.reason === void 0 ? {} : { reason: policy.reason }, checkedAt: new Date(nowMs).toISOString() }, null, 2)}
|
|
58313
|
+
`);
|
|
58314
|
+
renameSync5(temp, path);
|
|
58315
|
+
}
|
|
58316
|
+
var TaskNewResult = withDryRun(
|
|
58317
|
+
external_exports.object({ taskId: external_exports.string(), version: external_exports.number(), state: external_exports.string(), holder: external_exports.string(), priority: TaskPriority, rank: external_exports.number(), next: external_exports.string() })
|
|
58318
|
+
);
|
|
58319
|
+
var TaskNextResult = external_exports.object({ task: NextTask.shape.task, preempt: external_exports.boolean(), why: external_exports.string(), command: external_exports.string().nullable() });
|
|
58320
|
+
var TaskQueueResult = TaskQueue;
|
|
58321
|
+
var TaskPrioritiseResult = withDryRun(external_exports.object({ ...PrioritiseResult.shape, next: external_exports.string() }));
|
|
58322
|
+
var TaskPolicyResult = external_exports.object({ enforcement: TaskEnforcement, reason: external_exports.string().optional(), changedBy: external_exports.string().optional(), updatedAt: external_exports.string().optional(), localFile: external_exports.string() });
|
|
58323
|
+
var TaskPolicySetResult = withDryRun(TaskPolicyResult);
|
|
58324
|
+
var requestId3 = () => `cli-${randomUUID4()}`;
|
|
58325
|
+
function priorityOf(value, fallback) {
|
|
58326
|
+
const parsed = TaskPriority.safeParse(value ?? fallback);
|
|
58327
|
+
if (!parsed.success) throw new UsageError(`--priority must be one of ${TASK_PRIORITIES.join(", ")}`);
|
|
58328
|
+
return parsed.data;
|
|
58329
|
+
}
|
|
58330
|
+
var mcpExecutor = (name2) => name2 === "codex" ? "codex" : "claude-code";
|
|
58331
|
+
var commandFor = (entry) => `overlane task ${entry.state === "paused" ? "resume" : "start"} ${entry.taskId}`;
|
|
58332
|
+
async function taskNext(deps) {
|
|
58333
|
+
const project = await connectedProject(deps, "task");
|
|
58334
|
+
const call2 = serviceCall(deps, project.serviceUrl, project.token);
|
|
58335
|
+
const current2 = readTaskState(project.root)?.taskId;
|
|
58336
|
+
const query = `?executor=${mcpExecutor(detectExecutorName(deps.env))}${current2 === void 0 ? "" : `¤t=${encodeURIComponent(current2)}`}`;
|
|
58337
|
+
const next = await call2(NextTask, "GET", `${taskQueuePaths.next(project.binding.tenantId, project.binding.projectId)}${query}`);
|
|
58338
|
+
if (next.task === null) {
|
|
58339
|
+
say(deps, 'Nothing is ready or paused. Create work with `overlane task new "<title>"`.');
|
|
58340
|
+
return { data: { ...next, command: null } };
|
|
58341
|
+
}
|
|
58342
|
+
const command = commandFor(next.task);
|
|
58343
|
+
say(deps, `Next: ${next.task.taskId} (${next.task.priority}, ${next.task.state}) ${next.task.title}`);
|
|
58344
|
+
say(deps, next.why);
|
|
58345
|
+
if (next.preempt) say(deps, `This outranks your current task ${current2 ?? ""}: checkpoint it (\`overlane task checkpoint --summary "..." --next "..." --pause user\`), then run: ${command}`);
|
|
58346
|
+
else say(deps, `Run: ${command}`);
|
|
58347
|
+
return { data: { ...next, command } };
|
|
58348
|
+
}
|
|
58349
|
+
async function taskQueue(deps) {
|
|
58350
|
+
const project = await connectedProject(deps, "task");
|
|
58351
|
+
const queue = await serviceCall(deps, project.serviceUrl, project.token)(TaskQueue, "GET", taskQueuePaths.base(project.binding.tenantId, project.binding.projectId));
|
|
58352
|
+
if (queue.tasks.length === 0) say(deps, "The queue is empty.");
|
|
58353
|
+
for (const entry of queue.tasks) say(deps, `${entry.priority} ${entry.taskId} ${entry.state}${entry.pauseReason === void 0 ? "" : `/${entry.pauseReason}`} ${entry.title}`);
|
|
58354
|
+
return { data: queue };
|
|
58355
|
+
}
|
|
58356
|
+
async function prioritiseTask(deps, input2) {
|
|
58357
|
+
if (input2.taskId === void 0) throw new UsageError("prioritise needs exactly one TASK_ID");
|
|
58358
|
+
if (input2.priority === void 0) throw new UsageError("prioritise needs --priority P0|P1|P2|P3");
|
|
58359
|
+
const priority = priorityOf(input2.priority, void 0);
|
|
58360
|
+
const name2 = detectExecutorName(deps.env);
|
|
58361
|
+
let request;
|
|
58362
|
+
try {
|
|
58363
|
+
request = PrioritiseRequest.parse({ requestId: requestId3(), priority, top: input2.top, origin: name2 === "terminal" ? "user" : "agent", ...input2.reason === void 0 ? {} : { reason: input2.reason }, executor: executorFor(name2) });
|
|
58364
|
+
} catch (error62) {
|
|
58365
|
+
throw new UsageError(String(error62));
|
|
58366
|
+
}
|
|
58367
|
+
if (input2.dryRun) {
|
|
58368
|
+
const project2 = await offlineProject(deps, "task");
|
|
58369
|
+
return planOutcome(deps, dryRunPlan({ service: project2.serviceUrl, requests: [{ method: "POST", path: taskQueuePaths.prioritise(project2.binding.tenantId, project2.binding.projectId, input2.taskId), body: request }] }));
|
|
58370
|
+
}
|
|
58371
|
+
const project = await connectedProject(deps, "task");
|
|
58372
|
+
const result = await serviceCall(deps, project.serviceUrl, project.token)(PrioritiseResult, "POST", taskQueuePaths.prioritise(project.binding.tenantId, project.binding.projectId, input2.taskId), request);
|
|
58373
|
+
say(deps, `${result.taskId} is now ${result.priority}${input2.top ? " and first in its priority" : ""} (rank ${result.rank}).${result.changed ? "" : " Nothing changed."}`);
|
|
58374
|
+
return { data: { ...result, next: "overlane task next" } };
|
|
58375
|
+
}
|
|
58376
|
+
async function newTask(deps, input2) {
|
|
58377
|
+
const title = input2.title.replace(/\s+/g, " ").trim();
|
|
58378
|
+
if (title.length === 0) throw new UsageError('new needs a title: overlane task new "<title>"');
|
|
58379
|
+
const priority = priorityOf(input2.priority, "P1");
|
|
58380
|
+
const started = await startTask(deps, {
|
|
58381
|
+
outcome: title,
|
|
58382
|
+
criteria: input2.criteria.length > 0 ? input2.criteria : [`Complete: ${title}`],
|
|
58383
|
+
paths: input2.paths.length > 0 ? input2.paths : ["**"],
|
|
58384
|
+
checks: input2.checks,
|
|
58385
|
+
dryRun: input2.dryRun
|
|
58386
|
+
});
|
|
58387
|
+
const data = started?.data;
|
|
58388
|
+
if (data === void 0 || "dryRun" in data) return started;
|
|
58389
|
+
const begun = data;
|
|
58390
|
+
const project = await connectedProject(deps, "task");
|
|
58391
|
+
const name2 = detectExecutorName(deps.env);
|
|
58392
|
+
const request = PrioritiseRequest.parse({ requestId: requestId3(), priority, top: input2.top, origin: name2 === "terminal" ? "user" : "agent", executor: executorFor(name2) });
|
|
58393
|
+
try {
|
|
58394
|
+
const ranked = await serviceCall(deps, project.serviceUrl, project.token)(PrioritiseResult, "POST", taskQueuePaths.prioritise(project.binding.tenantId, project.binding.projectId, begun.taskId), request);
|
|
58395
|
+
say(deps, `Ranked ${begun.taskId} ${ranked.priority}${input2.top ? " (first)" : ""}.`);
|
|
58396
|
+
return { data: { taskId: begun.taskId, version: begun.version, state: begun.state, holder: begun.holder, priority: ranked.priority, rank: ranked.rank, next: begun.next } };
|
|
58397
|
+
} catch (error62) {
|
|
58398
|
+
warn(deps, `task ${begun.taskId} is claimed but could not be ranked (${error62 instanceof Error ? error62.message : String(error62)}); run \`overlane task prioritise ${begun.taskId} --priority ${priority}\``);
|
|
58399
|
+
return { data: { taskId: begun.taskId, version: begun.version, state: begun.state, holder: begun.holder, priority: "P1", rank: 0, next: begun.next } };
|
|
58400
|
+
}
|
|
58401
|
+
}
|
|
58402
|
+
async function showPolicy2(deps) {
|
|
58403
|
+
const project = await connectedProject(deps, "task");
|
|
58404
|
+
const policy = await serviceCall(deps, project.serviceUrl, project.token)(TaskPolicy, "GET", taskQueuePaths.policy(project.binding.tenantId, project.binding.projectId));
|
|
58405
|
+
writePolicyFile(project.root, policy, deps.now());
|
|
58406
|
+
say(deps, `Task requirement: ${policy.enforcement}${policy.reason === void 0 ? "" : ` (${policy.reason})`}.`);
|
|
58407
|
+
return { data: { ...policy, localFile: TASK_POLICY_PATH } };
|
|
58408
|
+
}
|
|
58409
|
+
async function setPolicy(deps, input2) {
|
|
58410
|
+
const enforcement = TaskEnforcement.safeParse(input2.enforcement);
|
|
58411
|
+
if (!enforcement.success) throw new UsageError(`set needs ${TASK_ENFORCEMENT.join(" or ")}`);
|
|
58412
|
+
const name2 = detectExecutorName(deps.env);
|
|
58413
|
+
const parsed = SetTaskPolicyRequest.safeParse({ requestId: requestId3(), enforcement: enforcement.data, ...input2.reason === void 0 ? {} : { reason: input2.reason }, executor: executorFor(name2) });
|
|
58414
|
+
if (!parsed.success) throw new UsageError(parsed.error.issues.map((issue2) => issue2.message).join("; "));
|
|
58415
|
+
if (input2.dryRun) {
|
|
58416
|
+
const project2 = await offlineProject(deps, "task");
|
|
58417
|
+
return planOutcome(
|
|
58418
|
+
deps,
|
|
58419
|
+
dryRunPlan({
|
|
58420
|
+
service: project2.serviceUrl,
|
|
58421
|
+
requests: [{ method: "PUT", path: taskQueuePaths.policy(project2.binding.tenantId, project2.binding.projectId), body: parsed.data, note: "only a signed-in owner or admin may change it" }],
|
|
58422
|
+
writes: [{ path: TASK_POLICY_PATH, action: "write", description: "this working copy's copy of the requirement (never committed)" }]
|
|
58423
|
+
})
|
|
58424
|
+
);
|
|
58425
|
+
}
|
|
58426
|
+
const project = await connectedProject(deps, "task");
|
|
58427
|
+
const policy = await serviceCall(deps, project.serviceUrl, project.token)(TaskPolicy, "PUT", taskQueuePaths.policy(project.binding.tenantId, project.binding.projectId), parsed.data);
|
|
58428
|
+
writePolicyFile(project.root, policy, deps.now());
|
|
58429
|
+
say(deps, policy.enforcement === "required" ? "Every change now needs an active task." : `The task requirement is relaxed (${policy.reason ?? "no reason"}). It shows in the context packet and the event stream.`);
|
|
58430
|
+
return { data: { ...policy, localFile: TASK_POLICY_PATH } };
|
|
58431
|
+
}
|
|
58432
|
+
async function startExisting(deps, taskId, dryRun) {
|
|
58433
|
+
const resumed = await resumeTask(deps, { taskId, dryRun });
|
|
58434
|
+
const data = resumed?.data;
|
|
58435
|
+
if (data === void 0 || "dryRun" in data) return resumed;
|
|
58436
|
+
return { data: { taskId: data.taskId, version: data.version, state: data.task.state, holder: data.holder, ...data.task.lease === void 0 ? {} : { leaseExpiresAt: data.task.lease.expiresAt }, next: "overlane task submit" } };
|
|
58437
|
+
}
|
|
58438
|
+
|
|
58439
|
+
// ../cli/src/commands/queue.ts
|
|
58440
|
+
var common3 = { needsAuth: true, needsNetwork: true };
|
|
58441
|
+
var PRIORITIES = ["P0", "P1", "P2", "P3"];
|
|
58442
|
+
var taskNewCommand = defineCommand({
|
|
58443
|
+
path: ["task", "new"],
|
|
58444
|
+
summary: "Create a task from a title, claim it for this working copy and rank it",
|
|
58445
|
+
description: "The quick way to get an active task, which every change needs. Creates a task with the title as its outcome (one default criterion and every path unless you pass --criterion and --path), claims it, and ranks it (default P1). Fails with exit 5 if this working copy already holds a task.",
|
|
58446
|
+
args: [{ name: "title", required: true, variadic: true, description: "What the task must achieve" }],
|
|
58447
|
+
flags: [
|
|
58448
|
+
{ name: "priority", type: "string", enum: PRIORITIES, default: "P1", description: "P0 is most urgent, P3 least" },
|
|
58449
|
+
{ name: "top", type: "boolean", description: "Put the task first within its priority" },
|
|
58450
|
+
{ name: "criterion", type: "string", multiple: true, value: "TEXT", description: "An acceptance criterion; repeat for more (default: the title)" },
|
|
58451
|
+
{ name: "path", type: "string", multiple: true, value: "GLOB", description: "A file pattern the task may change (default: everything)" },
|
|
58452
|
+
{ name: "check", type: "string", multiple: true, value: "ID:LEVEL", description: "A required check and its minimum evidence level, for example unit_tests:L2" }
|
|
58453
|
+
],
|
|
58454
|
+
examples: ['overlane task new "Fix login redirect"', 'overlane task new "Hotfix the build" --priority P0 --top'],
|
|
58455
|
+
effect: "write",
|
|
58456
|
+
...common3,
|
|
58457
|
+
keywords: ["new task", "create task", "no active task", "blocked no task", "start work", "need a task", "begin", "quick task"],
|
|
58458
|
+
result: TaskNewResult,
|
|
58459
|
+
handler: async (inv) => newTask(inv.deps, {
|
|
58460
|
+
title: inv.positionals.join(" "),
|
|
58461
|
+
priority: textFlag(inv, "priority"),
|
|
58462
|
+
top: boolFlag(inv, "top"),
|
|
58463
|
+
criteria: listFlag(inv, "criterion"),
|
|
58464
|
+
paths: listFlag(inv, "path"),
|
|
58465
|
+
checks: listFlag(inv, "check"),
|
|
58466
|
+
dryRun: inv.dryRun
|
|
58467
|
+
})
|
|
58468
|
+
});
|
|
58469
|
+
var taskNextCommand = defineCommand({
|
|
58470
|
+
path: ["task", "next"],
|
|
58471
|
+
summary: "Show the task to work on next, ordered by priority, then rank, then plan order",
|
|
58472
|
+
description: "Picks the best ready or paused task: P0 before P3, then rank, then milestone and dependency order. When this working copy holds a task and the next one outranks it, says so (preempt) and prints the commands to checkpoint and switch; the preempted task comes back through this command afterwards.",
|
|
58473
|
+
examples: ["overlane task next"],
|
|
58474
|
+
effect: "read",
|
|
58475
|
+
...common3,
|
|
58476
|
+
keywords: ["what next", "next task", "priority", "what should i work on", "pick work", "resume after", "queue"],
|
|
58477
|
+
result: TaskNextResult,
|
|
58478
|
+
handler: async (inv) => taskNext(inv.deps)
|
|
58479
|
+
});
|
|
58480
|
+
var taskQueueCommand = defineCommand({
|
|
58481
|
+
path: ["task", "queue"],
|
|
58482
|
+
summary: "List open tasks in the order they will be worked",
|
|
58483
|
+
description: "Lists ready, running, paused and blocked tasks by priority, then rank, then plan order, with each task's priority.",
|
|
58484
|
+
examples: ["overlane task queue"],
|
|
58485
|
+
effect: "read",
|
|
58486
|
+
...common3,
|
|
58487
|
+
keywords: ["priority list", "ranking", "order", "backlog", "what is queued", "p0"],
|
|
58488
|
+
result: TaskQueueResult,
|
|
58489
|
+
handler: async (inv) => taskQueue(inv.deps)
|
|
58490
|
+
});
|
|
58491
|
+
var taskPrioritiseCommand = defineCommand({
|
|
58492
|
+
path: ["task", "prioritise"],
|
|
58493
|
+
summary: "Set a task's priority (P0 to P3) and optionally put it first",
|
|
58494
|
+
description: "Re-ranks a task. Every change is a ledger event (`task.prioritised`). With --top the task goes first within its priority. A repeated identical call changes nothing.",
|
|
58495
|
+
args: [{ name: "task-id", required: true, description: "The task to re-rank" }],
|
|
58496
|
+
flags: [
|
|
58497
|
+
{ name: "priority", type: "string", required: true, enum: PRIORITIES, description: "P0 is most urgent, P3 least" },
|
|
58498
|
+
{ name: "top", type: "boolean", description: "Put the task first within its priority" },
|
|
58499
|
+
{ name: "reason", type: "string", value: "TEXT", description: "Why; kept in the event" }
|
|
58500
|
+
],
|
|
58501
|
+
examples: ["overlane task prioritise task-7 --priority P0 --top", 'overlane task prioritise task-9 --priority P2 --reason "user said later"'],
|
|
58502
|
+
effect: "write",
|
|
58503
|
+
...common3,
|
|
58504
|
+
keywords: ["reprioritize", "reprioritise", "bump", "urgent", "move to top", "rank", "lower priority", "p0", "p1", "p2", "p3"],
|
|
58505
|
+
result: TaskPrioritiseResult,
|
|
58506
|
+
handler: async (inv) => prioritiseTask(inv.deps, { taskId: inv.positionals[0], priority: textFlag(inv, "priority"), top: boolFlag(inv, "top"), reason: textFlag(inv, "reason"), dryRun: inv.dryRun })
|
|
58507
|
+
});
|
|
58508
|
+
var taskPolicyCommand = defineCommand({
|
|
58509
|
+
path: ["task", "policy"],
|
|
58510
|
+
summary: "Show whether changes need an active task, and refresh this working copy's copy",
|
|
58511
|
+
description: "Reads the project's task requirement (default `required`: edits and mutating shell commands are refused without an active task) and writes it to .harness/task-policy.json for the hooks.",
|
|
58512
|
+
examples: ["overlane task policy"],
|
|
58513
|
+
effect: "read",
|
|
58514
|
+
...common3,
|
|
58515
|
+
keywords: ["enforcement", "require task", "task gate", "relax", "blocked", "policy"],
|
|
58516
|
+
result: TaskPolicyResult,
|
|
58517
|
+
handler: async (inv) => showPolicy2(inv.deps)
|
|
58518
|
+
});
|
|
58519
|
+
var taskPolicySetCommand = defineCommand({
|
|
58520
|
+
path: ["task", "policy", "set"],
|
|
58521
|
+
summary: "Require, or relax, the active-task rule for the project (owners and admins)",
|
|
58522
|
+
description: "Sets the project's task requirement. Relaxing needs --reason and is recorded as a ledger event and shown in the context packet; it is never silent. Agent tokens cannot change it.",
|
|
58523
|
+
args: [{ name: "enforcement", required: true, description: "required or relaxed" }],
|
|
58524
|
+
flags: [{ name: "reason", type: "string", value: "TEXT", description: "Why the rule is relaxed (required for relaxed)" }],
|
|
58525
|
+
examples: ["overlane task policy set required", 'overlane task policy set relaxed --reason "docs-only repository"'],
|
|
58526
|
+
effect: "write",
|
|
58527
|
+
...common3,
|
|
58528
|
+
keywords: ["relax", "turn off task requirement", "require tasks", "allow edits without task", "enforcement"],
|
|
58529
|
+
result: TaskPolicySetResult,
|
|
58530
|
+
handler: async (inv) => setPolicy(inv.deps, { enforcement: inv.positionals[0], reason: textFlag(inv, "reason"), dryRun: inv.dryRun })
|
|
58531
|
+
});
|
|
58532
|
+
var queueCommands = [taskNewCommand, taskNextCommand, taskQueueCommand, taskPrioritiseCommand, taskPolicyCommand, taskPolicySetCommand];
|
|
58533
|
+
|
|
58232
58534
|
// ../cli/src/task/results.ts
|
|
58233
58535
|
init_zod();
|
|
58234
58536
|
var TaskListResult = external_exports.object({ tasks: external_exports.array(TaskSummary) });
|
|
@@ -58267,34 +58569,35 @@ var TaskHandoffResult = withDryRun(
|
|
|
58267
58569
|
);
|
|
58268
58570
|
|
|
58269
58571
|
// ../cli/src/commands/task.ts
|
|
58270
|
-
var
|
|
58572
|
+
var common4 = { needsAuth: true, needsNetwork: true };
|
|
58271
58573
|
var taskListCommand = defineCommand({
|
|
58272
58574
|
path: ["task", "list"],
|
|
58273
58575
|
summary: "List the project's tasks and their states",
|
|
58274
58576
|
description: "Lists every task of the connected project with its state, pause reason, version, lease holder, checks and latest checkpoint.",
|
|
58275
58577
|
examples: ["overlane task list"],
|
|
58276
58578
|
effect: "read",
|
|
58277
|
-
...
|
|
58579
|
+
...common4,
|
|
58278
58580
|
keywords: ["tasks", "show all tasks", "see tasks", "backlog", "what tasks exist", "work items"],
|
|
58279
58581
|
result: TaskListResult,
|
|
58280
58582
|
handler: async (inv) => listTasks(inv.deps)
|
|
58281
58583
|
});
|
|
58282
58584
|
var taskStartCommand = defineCommand({
|
|
58283
58585
|
path: ["task", "start"],
|
|
58284
|
-
summary: "
|
|
58285
|
-
description: "
|
|
58586
|
+
summary: "Claim an existing task, or create one with a contract and claim it",
|
|
58587
|
+
description: "With a TASK_ID, claims that ready or paused task for this working copy (same checks as `task resume`). Without one, creates a task (outcome, acceptance criteria, required checks, allowed paths) at the current commit and claims it, writing the lease to .harness/task.json. Fails with exit 5 if this working copy already holds a task.",
|
|
58588
|
+
args: [{ name: "task-id", required: false, description: "An existing task to claim; omit to create one from the flags" }],
|
|
58286
58589
|
flags: [
|
|
58287
|
-
{ name: "outcome", type: "string",
|
|
58288
|
-
{ name: "criterion", type: "string", multiple: true,
|
|
58590
|
+
{ name: "outcome", type: "string", value: "TEXT", description: "What the task must achieve (up to 500 characters)" },
|
|
58591
|
+
{ name: "criterion", type: "string", multiple: true, value: "TEXT", description: "An acceptance criterion; repeat for more" },
|
|
58289
58592
|
{ name: "check", type: "string", multiple: true, value: "ID:LEVEL", description: "A required check and its minimum evidence level, for example unit_tests:L2; repeat for more" },
|
|
58290
|
-
{ name: "path", type: "string", multiple: true,
|
|
58593
|
+
{ name: "path", type: "string", multiple: true, value: "GLOB", description: "A file pattern the task may change; repeat for more" }
|
|
58291
58594
|
],
|
|
58292
|
-
examples: ['overlane task start --outcome "Add CSV export" --criterion "export works" --check unit_tests:L2 --path "src/**"', 'overlane task start --outcome "Fix login" --criterion "login passes" --path "src/auth/**" --dry-run'],
|
|
58595
|
+
examples: ["overlane task start task-7", 'overlane task start --outcome "Add CSV export" --criterion "export works" --check unit_tests:L2 --path "src/**"', 'overlane task start --outcome "Fix login" --criterion "login passes" --path "src/auth/**" --dry-run'],
|
|
58293
58596
|
effect: "write",
|
|
58294
|
-
...
|
|
58597
|
+
...common4,
|
|
58295
58598
|
keywords: ["begin", "create task", "new task", "open", "claim new", "work item", "contract", "acceptance criteria", "start working"],
|
|
58296
58599
|
result: TaskStartResult,
|
|
58297
|
-
handler: async (inv) => startTask(inv.deps, { outcome: textFlag(inv, "outcome"), criteria: listFlag(inv, "criterion"), paths: listFlag(inv, "path"), checks: listFlag(inv, "check"), dryRun: inv.dryRun })
|
|
58600
|
+
handler: async (inv) => inv.positionals[0] !== void 0 ? startExisting(inv.deps, inv.positionals[0], inv.dryRun) : startTask(inv.deps, { outcome: textFlag(inv, "outcome"), criteria: listFlag(inv, "criterion"), paths: listFlag(inv, "path"), checks: listFlag(inv, "check"), dryRun: inv.dryRun })
|
|
58298
58601
|
});
|
|
58299
58602
|
var taskStatusCommand = defineCommand({
|
|
58300
58603
|
path: ["task", "status"],
|
|
@@ -58302,7 +58605,7 @@ var taskStatusCommand = defineCommand({
|
|
|
58302
58605
|
description: "Shows the held task from the service: state, lease, acceptance criteria, checks, evidence count and the latest checkpoint. Says so when nothing is held or the lease was lost.",
|
|
58303
58606
|
examples: ["overlane task status"],
|
|
58304
58607
|
effect: "read",
|
|
58305
|
-
...
|
|
58608
|
+
...common4,
|
|
58306
58609
|
keywords: ["current task", "what am i working on", "lease", "active task", "progress", "held task"],
|
|
58307
58610
|
result: TaskStatusResult,
|
|
58308
58611
|
handler: async (inv) => taskStatus(inv.deps)
|
|
@@ -58318,7 +58621,7 @@ var taskCheckpointCommand = defineCommand({
|
|
|
58318
58621
|
],
|
|
58319
58622
|
examples: ['overlane task checkpoint --summary "Parser done" --next "Write the tests"', 'overlane task checkpoint --summary "Out of budget" --next "Resume" --pause quota'],
|
|
58320
58623
|
effect: "write",
|
|
58321
|
-
...
|
|
58624
|
+
...common4,
|
|
58322
58625
|
keywords: ["save", "progress", "pause", "stop work", "park", "quota", "limit reached", "remember place", "snapshot", "save state", "out of budget"],
|
|
58323
58626
|
result: TaskCheckpointResult,
|
|
58324
58627
|
handler: async (inv) => checkpointTask(inv.deps, { summary: textFlag(inv, "summary"), next: textFlag(inv, "next"), pause: textFlag(inv, "pause"), dryRun: inv.dryRun })
|
|
@@ -58330,7 +58633,7 @@ var taskResumeCommand = defineCommand({
|
|
|
58330
58633
|
args: [{ name: "task-id", required: true, description: "The task to resume" }],
|
|
58331
58634
|
examples: ["overlane task resume task-1"],
|
|
58332
58635
|
effect: "write",
|
|
58333
|
-
...
|
|
58636
|
+
...common4,
|
|
58334
58637
|
keywords: ["continue", "pick up", "restart", "reclaim", "after pause", "take over", "carry on"],
|
|
58335
58638
|
result: TaskResumeResult,
|
|
58336
58639
|
handler: async (inv) => resumeTask(inv.deps, { taskId: inv.positionals[0], dryRun: inv.dryRun })
|
|
@@ -58341,7 +58644,7 @@ var taskSubmitCommand = defineCommand({
|
|
|
58341
58644
|
description: "Asks for verification at HEAD. The task is verified only when evidence at or above each required check's level exists for that commit: L2 comes from CI on the pushed commit, L1 from `overlane task evidence`.",
|
|
58342
58645
|
examples: ["overlane task submit", "overlane task submit --dry-run"],
|
|
58343
58646
|
effect: "write",
|
|
58344
|
-
...
|
|
58647
|
+
...common4,
|
|
58345
58648
|
keywords: ["finish", "done", "complete", "verify", "ready for review", "request verification", "hand in", "turn in"],
|
|
58346
58649
|
result: TaskSubmitResult,
|
|
58347
58650
|
handler: async (inv) => submitTask(inv.deps, { dryRun: inv.dryRun })
|
|
@@ -58357,7 +58660,7 @@ var taskEvidenceCommand = defineCommand({
|
|
|
58357
58660
|
],
|
|
58358
58661
|
examples: ["overlane task evidence --level L1 -- pnpm test"],
|
|
58359
58662
|
effect: "write",
|
|
58360
|
-
...
|
|
58663
|
+
...common4,
|
|
58361
58664
|
keywords: ["tests", "prove", "record test result", "verification", "run checks", "L1", "attest", "run the tests and record"],
|
|
58362
58665
|
result: TaskEvidenceResult,
|
|
58363
58666
|
handler: async (inv) => recordEvidence(inv.deps, { level: textFlag(inv, "level"), task: textFlag(inv, "task"), words: inv.positionals, dryRun: inv.dryRun })
|
|
@@ -58373,7 +58676,7 @@ var taskHandoffCommand = defineCommand({
|
|
|
58373
58676
|
],
|
|
58374
58677
|
examples: ["overlane task handoff --to codex", 'overlane task handoff --to claude --summary "API done" --next "Add tests"'],
|
|
58375
58678
|
effect: "write",
|
|
58376
|
-
...
|
|
58679
|
+
...common4,
|
|
58377
58680
|
keywords: ["hand off", "transfer", "give to", "switch agent", "other agent", "codex", "claude", "pass the task", "delegate", "move work", "swap agents"],
|
|
58378
58681
|
result: TaskHandoffResult,
|
|
58379
58682
|
handler: async (inv) => handoffTask(inv.deps, { summary: textFlag(inv, "summary"), next: textFlag(inv, "next"), to: textFlag(inv, "to"), dryRun: inv.dryRun })
|
|
@@ -58393,6 +58696,7 @@ function coreCommands() {
|
|
|
58393
58696
|
doctorCommand,
|
|
58394
58697
|
disconnectCommand,
|
|
58395
58698
|
...taskCommands,
|
|
58699
|
+
...queueCommands,
|
|
58396
58700
|
...runCommands,
|
|
58397
58701
|
...releaseCommands,
|
|
58398
58702
|
...identityCommands
|
|
@@ -58614,35 +58918,35 @@ init_src2();
|
|
|
58614
58918
|
|
|
58615
58919
|
// src/data-dir.ts
|
|
58616
58920
|
import { homedir } from "node:os";
|
|
58617
|
-
import { join as
|
|
58921
|
+
import { join as join25 } from "node:path";
|
|
58618
58922
|
function dataDir(env = process.env, home = homedir()) {
|
|
58619
58923
|
const override = env["MVRX_DATA_DIR"];
|
|
58620
58924
|
if (override !== void 0 && override !== "") return override;
|
|
58621
|
-
const base2 = env["XDG_DATA_HOME"] ?? (process.platform === "win32" ? env["LOCALAPPDATA"] : void 0) ?? (process.platform === "darwin" ?
|
|
58622
|
-
return
|
|
58925
|
+
const base2 = env["XDG_DATA_HOME"] ?? (process.platform === "win32" ? env["LOCALAPPDATA"] : void 0) ?? (process.platform === "darwin" ? join25(home, "Library", "Application Support") : join25(home, ".local", "share"));
|
|
58926
|
+
return join25(base2, "mvrx-harness");
|
|
58623
58927
|
}
|
|
58624
58928
|
function marketplaceRoot(env = process.env, home = homedir()) {
|
|
58625
|
-
return
|
|
58929
|
+
return join25(dataDir(env, home), "marketplace");
|
|
58626
58930
|
}
|
|
58627
58931
|
|
|
58628
58932
|
// src/plugin.ts
|
|
58629
58933
|
import { readFileSync as readFileSync6 } from "node:fs";
|
|
58630
|
-
import { join as
|
|
58934
|
+
import { join as join27 } from "node:path";
|
|
58631
58935
|
import { parseArgs as parseArgs3 } from "node:util";
|
|
58632
58936
|
|
|
58633
58937
|
// src/marketplace.ts
|
|
58634
58938
|
init_src();
|
|
58635
58939
|
import { createHash as createHash7 } from "node:crypto";
|
|
58636
|
-
import { cpSync, existsSync as existsSync5, mkdirSync as
|
|
58637
|
-
import { dirname as
|
|
58940
|
+
import { cpSync, existsSync as existsSync5, mkdirSync as mkdirSync8, readdirSync as readdirSync3, readFileSync as readFileSync5, renameSync as renameSync6, rmSync as rmSync4, statSync, writeFileSync as writeFileSync7 } from "node:fs";
|
|
58941
|
+
import { dirname as dirname8, join as join26, relative, sep } from "node:path";
|
|
58638
58942
|
var CLIENT_DIRS = ["claude", "codex"];
|
|
58639
58943
|
var EMBEDDED_MANIFEST = "release-manifest.json";
|
|
58640
|
-
var INSTALLED_MANIFEST =
|
|
58944
|
+
var INSTALLED_MANIFEST = join26(".release", "manifest.json");
|
|
58641
58945
|
var MarketplaceError = class extends Error {
|
|
58642
58946
|
};
|
|
58643
58947
|
function loadEmbedded(packageRoot2) {
|
|
58644
|
-
const dir =
|
|
58645
|
-
const path =
|
|
58948
|
+
const dir = join26(packageRoot2, "plugins");
|
|
58949
|
+
const path = join26(dir, EMBEDDED_MANIFEST);
|
|
58646
58950
|
if (!existsSync5(path)) throw new MarketplaceError(`this package has no embedded plugin release (${path} is missing)`);
|
|
58647
58951
|
const parsed = ReleaseManifest.safeParse(JSON.parse(readFileSync5(path, "utf8")));
|
|
58648
58952
|
if (!parsed.success) throw new MarketplaceError(`the embedded release manifest is invalid: ${parsed.error.message}`);
|
|
@@ -58655,7 +58959,7 @@ function listFiles(root, dir = root) {
|
|
|
58655
58959
|
if (!existsSync5(dir)) return [];
|
|
58656
58960
|
const out2 = [];
|
|
58657
58961
|
for (const entry of readdirSync3(dir, { withFileTypes: true })) {
|
|
58658
|
-
const full =
|
|
58962
|
+
const full = join26(dir, entry.name);
|
|
58659
58963
|
if (entry.isDirectory()) out2.push(...listFiles(root, full));
|
|
58660
58964
|
else out2.push(relative(root, full).split(sep).join("/"));
|
|
58661
58965
|
}
|
|
@@ -58667,7 +58971,7 @@ async function verifyTree(treeRoot, manifest) {
|
|
|
58667
58971
|
if (recomputed !== manifest.digest) problems.push(`manifest digest ${manifest.digest} does not match its file list (${recomputed})`);
|
|
58668
58972
|
const listed = new Set(manifest.files.map((file2) => file2.path));
|
|
58669
58973
|
for (const file2 of manifest.files) {
|
|
58670
|
-
const path =
|
|
58974
|
+
const path = join26(treeRoot, file2.path);
|
|
58671
58975
|
if (!existsSync5(path)) {
|
|
58672
58976
|
problems.push(`missing: ${file2.path}`);
|
|
58673
58977
|
continue;
|
|
@@ -58675,7 +58979,7 @@ async function verifyTree(treeRoot, manifest) {
|
|
|
58675
58979
|
if (sha2562(readFileSync5(path)) !== file2.digest) problems.push(`modified: ${file2.path}`);
|
|
58676
58980
|
}
|
|
58677
58981
|
for (const client of CLIENT_DIRS) {
|
|
58678
|
-
for (const found of listFiles(
|
|
58982
|
+
for (const found of listFiles(join26(treeRoot, client))) {
|
|
58679
58983
|
if (!listed.has(`${client}/${found}`)) problems.push(`unlisted: ${client}/${found}`);
|
|
58680
58984
|
}
|
|
58681
58985
|
}
|
|
@@ -58683,7 +58987,7 @@ async function verifyTree(treeRoot, manifest) {
|
|
|
58683
58987
|
}
|
|
58684
58988
|
function readInstalledManifest(target) {
|
|
58685
58989
|
try {
|
|
58686
|
-
const parsed = ReleaseManifest.safeParse(JSON.parse(readFileSync5(
|
|
58990
|
+
const parsed = ReleaseManifest.safeParse(JSON.parse(readFileSync5(join26(target, INSTALLED_MANIFEST), "utf8")));
|
|
58687
58991
|
return parsed.success ? parsed.data : null;
|
|
58688
58992
|
} catch {
|
|
58689
58993
|
return null;
|
|
@@ -58708,23 +59012,23 @@ async function syncMarketplace(embedded, target) {
|
|
|
58708
59012
|
const staging = `${target}.new-${process.pid}`;
|
|
58709
59013
|
const previous = `${target}.old-${process.pid}`;
|
|
58710
59014
|
rmSync4(staging, { recursive: true, force: true });
|
|
58711
|
-
|
|
59015
|
+
mkdirSync8(staging, { recursive: true });
|
|
58712
59016
|
try {
|
|
58713
59017
|
for (const client of CLIENT_DIRS) {
|
|
58714
|
-
if (existsSync5(
|
|
59018
|
+
if (existsSync5(join26(embedded.dir, client))) cpSync(join26(embedded.dir, client), join26(staging, client), { recursive: true });
|
|
58715
59019
|
}
|
|
58716
|
-
|
|
58717
|
-
|
|
59020
|
+
mkdirSync8(join26(staging, ".release"), { recursive: true });
|
|
59021
|
+
writeFileSync7(join26(staging, INSTALLED_MANIFEST), `${JSON.stringify(embedded.manifest, null, 2)}
|
|
58718
59022
|
`);
|
|
58719
59023
|
const after = await verifyTree(staging, embedded.manifest);
|
|
58720
59024
|
if (after.length > 0) throw new MarketplaceError(`the copied plugin files do not match the release manifest:
|
|
58721
59025
|
${after.join("\n ")}`);
|
|
58722
|
-
|
|
58723
|
-
if (existsSync5(target))
|
|
59026
|
+
mkdirSync8(dirname8(target), { recursive: true });
|
|
59027
|
+
if (existsSync5(target)) renameSync6(target, previous);
|
|
58724
59028
|
try {
|
|
58725
|
-
|
|
59029
|
+
renameSync6(staging, target);
|
|
58726
59030
|
} catch (error62) {
|
|
58727
|
-
if (existsSync5(previous))
|
|
59031
|
+
if (existsSync5(previous)) renameSync6(previous, target);
|
|
58728
59032
|
throw error62;
|
|
58729
59033
|
}
|
|
58730
59034
|
rmSync4(previous, { recursive: true, force: true });
|
|
@@ -58746,7 +59050,7 @@ var PLUGIN_USAGE = ` overlane plugin install [--scope project|user] [--client c
|
|
|
58746
59050
|
var PluginUsageError = class extends Error {
|
|
58747
59051
|
};
|
|
58748
59052
|
function readNames(treeRoot, client) {
|
|
58749
|
-
const file2 = client === "claude" ?
|
|
59053
|
+
const file2 = client === "claude" ? join27(treeRoot, "claude", ".claude-plugin", "marketplace.json") : join27(treeRoot, "codex", ".agents", "plugins", "marketplace.json");
|
|
58750
59054
|
const parsed = JSON.parse(readFileSync6(file2, "utf8"));
|
|
58751
59055
|
const record2 = parsed;
|
|
58752
59056
|
const plugin = record2.plugins?.[0]?.name;
|
|
@@ -58793,7 +59097,7 @@ ${PLUGIN_USAGE}`);
|
|
|
58793
59097
|
const key = `${names.plugin}@${names.marketplace}`;
|
|
58794
59098
|
if (!await available(deps, client)) {
|
|
58795
59099
|
if (explicit !== void 0) {
|
|
58796
|
-
deps.stderr(`overlane: \`${client}\` was not found on PATH; the marketplace is at ${
|
|
59100
|
+
deps.stderr(`overlane: \`${client}\` was not found on PATH; the marketplace is at ${join27(root, client)}
|
|
58797
59101
|
`);
|
|
58798
59102
|
failed = true;
|
|
58799
59103
|
} else {
|
|
@@ -58805,7 +59109,7 @@ ${PLUGIN_USAGE}`);
|
|
|
58805
59109
|
ranAny = true;
|
|
58806
59110
|
deps.stdout(`${client}:
|
|
58807
59111
|
`);
|
|
58808
|
-
const dir =
|
|
59112
|
+
const dir = join27(root, client);
|
|
58809
59113
|
const steps = client === "claude" ? [
|
|
58810
59114
|
["claude", ["plugin", "marketplace", "add", dir, "--scope", scope]],
|
|
58811
59115
|
["claude", ["plugin", "marketplace", "update", names.marketplace]],
|
|
@@ -58973,7 +59277,7 @@ var packageCommands = [indexBuildCommand, indexUploadCommand, shimCommand, plugi
|
|
|
58973
59277
|
// src/deps.ts
|
|
58974
59278
|
import { execFile as execFile3, spawn } from "node:child_process";
|
|
58975
59279
|
import { homedir as homedir3 } from "node:os";
|
|
58976
|
-
import { join as
|
|
59280
|
+
import { join as join30 } from "node:path";
|
|
58977
59281
|
import { createInterface } from "node:readline/promises";
|
|
58978
59282
|
function exec(command, args2, options) {
|
|
58979
59283
|
return new Promise((resolveResult) => {
|
|
@@ -59019,8 +59323,8 @@ async function confirm(question) {
|
|
|
59019
59323
|
}
|
|
59020
59324
|
}
|
|
59021
59325
|
function configDir2(env) {
|
|
59022
|
-
const base2 = env["XDG_CONFIG_HOME"] ?? (process.platform === "win32" ? env["APPDATA"] : void 0) ??
|
|
59023
|
-
return
|
|
59326
|
+
const base2 = env["XDG_CONFIG_HOME"] ?? (process.platform === "win32" ? env["APPDATA"] : void 0) ?? join30(homedir3(), ".config");
|
|
59327
|
+
return join30(base2, "mvrx-harness");
|
|
59024
59328
|
}
|
|
59025
59329
|
function createDeps2(env = process.env) {
|
|
59026
59330
|
return {
|