@brainervirus/workit-cli 1.1.1 → 1.2.1
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/index.js +268 -78
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -43278,7 +43278,7 @@ import path11 from "node:path";
|
|
|
43278
43278
|
var SUPPORT_MATRIX = {
|
|
43279
43279
|
bun: "1.4.1",
|
|
43280
43280
|
node: { minimum: "24", current: "24.20.0" },
|
|
43281
|
-
opencode: { minimum: "1.
|
|
43281
|
+
opencode: { minimum: "1.18.30", current: "1.18.30" },
|
|
43282
43282
|
codex: { cli: "0.153.4", desktopPackage: "26.901.20858", bundledCodexCli: "0.153.0-alpha.5" },
|
|
43283
43283
|
os: ["ubuntu-latest", "macos-latest", "windows-latest"]
|
|
43284
43284
|
};
|
|
@@ -51105,6 +51105,7 @@ var workerSchema = object({
|
|
|
51105
51105
|
assignment: assignmentSchema,
|
|
51106
51106
|
state: _enum(["assigned", "dispatching", "running", "cancelling", "stopped", "unknown"]),
|
|
51107
51107
|
session: refSchema.nullable(),
|
|
51108
|
+
coordinator: refSchema.optional(),
|
|
51108
51109
|
report: workerReportSchema.nullable()
|
|
51109
51110
|
}).strict();
|
|
51110
51111
|
var ownerSchema = object({
|
|
@@ -51216,6 +51217,7 @@ var taskSummarySchema = object({
|
|
|
51216
51217
|
requirements: array(requirementEvaluationSchema),
|
|
51217
51218
|
writer: workspaceRecordSchema.shape.writer
|
|
51218
51219
|
}).strict();
|
|
51220
|
+
var taskListItemSchema = taskSummarySchema.omit({ policy: true, requirements: true });
|
|
51219
51221
|
var exportBundleSchema = object({
|
|
51220
51222
|
schemaVersion: literal(1),
|
|
51221
51223
|
exportedAt: utc,
|
|
@@ -51237,11 +51239,15 @@ var taskOperations = {
|
|
|
51237
51239
|
expectedWorkspaceRevision: revision.nullable().optional(),
|
|
51238
51240
|
intent: intentSchema
|
|
51239
51241
|
}),
|
|
51240
|
-
list: operation({
|
|
51242
|
+
list: operation({
|
|
51243
|
+
action: literal("list"),
|
|
51244
|
+
status: _enum(["open", "closed", "all"]).optional(),
|
|
51245
|
+
limit: number2().int().min(1).max(50).optional()
|
|
51246
|
+
}),
|
|
51241
51247
|
inspect: operation({
|
|
51242
51248
|
action: literal("inspect"),
|
|
51243
51249
|
...taskId,
|
|
51244
|
-
view: _enum(["summary", "full"])
|
|
51250
|
+
view: _enum(["summary", "full"]).optional()
|
|
51245
51251
|
}),
|
|
51246
51252
|
revise: operation({
|
|
51247
51253
|
action: literal("revise"),
|
|
@@ -51269,7 +51275,7 @@ var taskOperations = {
|
|
|
51269
51275
|
...taskId,
|
|
51270
51276
|
...revisions,
|
|
51271
51277
|
expectedWorkspaceRevision: revision.optional(),
|
|
51272
|
-
authorityRefs: array(refSchema)
|
|
51278
|
+
authorityRefs: array(refSchema).optional()
|
|
51273
51279
|
}),
|
|
51274
51280
|
close: operation({
|
|
51275
51281
|
action: literal("close"),
|
|
@@ -58253,6 +58259,10 @@ var validPath = (value) => typeof value === "string" && value.length > 0 && ![..
|
|
|
58253
58259
|
}) && !value.split(/[\\/]/).includes("..");
|
|
58254
58260
|
var callerValue = (value) => ({ host: value.host, actor: value.actor });
|
|
58255
58261
|
var workerIdOf = (value) => value.workerId ?? null;
|
|
58262
|
+
var currentWriterOwnsTask = (task, workspace, caller) => {
|
|
58263
|
+
const owner = workspace.writer?.owner;
|
|
58264
|
+
return task.status === "active" && task.workspaceId === workspace.id && owner?.taskId === task.id && owner.session.host === caller.host && owner.session.handle === caller.actor;
|
|
58265
|
+
};
|
|
58256
58266
|
function assertProductWriteAllowed(input) {
|
|
58257
58267
|
if (!Array.isArray(input.paths) || input.paths.some((path) => !validPath(path)))
|
|
58258
58268
|
return failure("invalid_input", "invalid product write path");
|
|
@@ -58958,9 +58968,11 @@ var standingReceiptFor = (root, workspace, cls, dir) => {
|
|
|
58958
58968
|
var verifyStandingApproval = (root, task, caller, binding) => {
|
|
58959
58969
|
if (task.status !== "active")
|
|
58960
58970
|
return failure("invalid_transition", "only active tasks can authorize actions");
|
|
58961
|
-
const
|
|
58962
|
-
if (!
|
|
58963
|
-
return
|
|
58971
|
+
const workspace = new TaskStore(root).readWorkspace();
|
|
58972
|
+
if (!workspace.ok)
|
|
58973
|
+
return workspace;
|
|
58974
|
+
if (!workspace.data || !currentWriterOwnsTask(task, workspace.data, caller))
|
|
58975
|
+
return failure("permission_denied", "standing approval requires the current writer session");
|
|
58964
58976
|
const standing = binding.standing;
|
|
58965
58977
|
if (!standing || typeof standing.workspace !== "string" || typeof standing.class !== "string")
|
|
58966
58978
|
return failure("invalid_input", "standing approval needs a workspace and class");
|
|
@@ -59008,14 +59020,14 @@ var standingAutoApplies = (store, host, actor, operation) => {
|
|
|
59008
59020
|
const workspace = store.readWorkspace();
|
|
59009
59021
|
if (!listed.ok || !workspace.ok || !workspace.data)
|
|
59010
59022
|
return null;
|
|
59011
|
-
const
|
|
59012
|
-
if (
|
|
59023
|
+
const task = listed.data.find((task) => currentWriterOwnsTask(task, workspace.data, { host, actor }));
|
|
59024
|
+
if (!task)
|
|
59013
59025
|
return null;
|
|
59014
59026
|
const resolved = resolveAutoApproval(store.root);
|
|
59015
59027
|
if (resolved.status !== "on")
|
|
59016
59028
|
return null;
|
|
59017
59029
|
return {
|
|
59018
|
-
task
|
|
59030
|
+
task,
|
|
59019
59031
|
workspaceId: workspace.data.id,
|
|
59020
59032
|
workspaceRevision: workspace.data.revision,
|
|
59021
59033
|
cls,
|
|
@@ -59274,6 +59286,20 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
59274
59286
|
};
|
|
59275
59287
|
var verifyContentRefs = (store, binding) => verifyDecisionContentAtRoot(store.root, binding);
|
|
59276
59288
|
var storedDecisionApplicable = (store, task, purpose, binding) => task.decisions.filter((entry) => entry.provenance.kind !== "imported" && decisionMatches(entry, purpose, binding) && verifyDecisionContentAtRoot(store.root, entry.data.binding).ok);
|
|
59289
|
+
var approvalAuthorityMatches = (store, task, approval, current) => {
|
|
59290
|
+
if (approval.kind !== "host_observed" || approval.receipts.length === 0)
|
|
59291
|
+
return false;
|
|
59292
|
+
if (provenanceMatches(approval, current))
|
|
59293
|
+
return true;
|
|
59294
|
+
const session = current.kind === "host_observed" ? current.session : null;
|
|
59295
|
+
if (!session || session.kind !== "host")
|
|
59296
|
+
return false;
|
|
59297
|
+
const workspace = store.readWorkspace();
|
|
59298
|
+
return workspace.ok && workspace.data !== null && currentWriterOwnsTask(task, workspace.data, {
|
|
59299
|
+
host: session.host,
|
|
59300
|
+
actor: session.handle
|
|
59301
|
+
});
|
|
59302
|
+
};
|
|
59277
59303
|
var validateAction = (store, task, workspaceId, input, authority) => {
|
|
59278
59304
|
if (task.status !== "active")
|
|
59279
59305
|
return failure("invalid_transition", "only active tasks can authorize actions");
|
|
@@ -59299,7 +59325,7 @@ var validateAction = (store, task, workspaceId, input, authority) => {
|
|
|
59299
59325
|
return failure("permission_denied", "native reservation authority does not match decision");
|
|
59300
59326
|
if (decision.response !== "approved")
|
|
59301
59327
|
return failure("permission_denied", "decision was rejected");
|
|
59302
|
-
if (
|
|
59328
|
+
if (!approvalAuthorityMatches(store, task, entry.provenance, authority.provenance))
|
|
59303
59329
|
return failure("permission_denied", "action approval lacks native receipt assurance");
|
|
59304
59330
|
const receipts = entry.provenance.receipts;
|
|
59305
59331
|
const standing = receipts.filter((receipt) => typeof receipt === "object" && receipt !== null && receipt.kind === "standing");
|
|
@@ -59466,7 +59492,7 @@ function settleAction(input) {
|
|
|
59466
59492
|
return failure("not_found", "decision not found");
|
|
59467
59493
|
if (!authorityDecisionMatches(authority, entry.data))
|
|
59468
59494
|
return failure("permission_denied", "native settlement authority does not match decision");
|
|
59469
|
-
if (!
|
|
59495
|
+
if (!approvalAuthorityMatches(input.store, current, entry.provenance, authority.provenance))
|
|
59470
59496
|
return failure("permission_denied", "native settlement caller does not match approval");
|
|
59471
59497
|
if (entry.data.purpose !== "action" || entry.data.digest !== decisionDigest(entry.data))
|
|
59472
59498
|
return failure("permission_denied", "decision binding is invalid");
|
|
@@ -59565,7 +59591,7 @@ function reconcileAction(input) {
|
|
|
59565
59591
|
const entry = current.decisions.find((candidate) => candidate.id === input.decisionId);
|
|
59566
59592
|
if (!entry || entry.data.purpose !== "action")
|
|
59567
59593
|
return failure("not_found", "decision not found");
|
|
59568
|
-
if (!authorityDecisionMatches(authority, entry.data) || !
|
|
59594
|
+
if (!authorityDecisionMatches(authority, entry.data) || !approvalAuthorityMatches(input.store, current, entry.provenance, authority.provenance))
|
|
59569
59595
|
return failure("permission_denied", "native reconciliation caller does not match approval");
|
|
59570
59596
|
if (entry.data.response !== "approved" || entry.data.revoked !== null || entry.data.digest !== decisionDigest(entry.data) || entry.data.binding.taskId !== current.id || entry.data.binding.workspaceId !== current.workspaceId || entry.data.binding.workspaceId !== workspace.data.id)
|
|
59571
59597
|
return failure("permission_denied", "reconciliation decision binding is invalid");
|
|
@@ -59902,7 +59928,7 @@ var resolveBinding = (evidence, pin, currentCandidateId) => {
|
|
|
59902
59928
|
candidateId: evidence.candidateId ?? fallback
|
|
59903
59929
|
};
|
|
59904
59930
|
};
|
|
59905
|
-
var findingVerificationPasses = (findingCandidateId, evidence) => evidence.status === "passed" && (evidence.kind === "check" || evidence.kind === "review") && ((findingCandidateId ?? null) === null || evidence.candidateId
|
|
59931
|
+
var findingVerificationPasses = (findingCandidateId, evidence) => evidence.status === "passed" && (evidence.kind === "check" || evidence.kind === "review") && ((findingCandidateId ?? null) === null || evidence.candidateId != null);
|
|
59906
59932
|
var applicableDecision2 = (task, workspace, requirement, checkoutRoot) => task.decisions.filter((entry) => entry.provenance.kind !== "imported").map((entry) => entry.data).filter((decision) => decision.purpose === "limitation" && decision.response === "approved" && decision.revoked === null && decision.binding.taskId === task.id && decision.binding.workspaceId === workspace.id && decision.requirementIds.includes(requirement.id) && decision.binding.scope && scopeCovers2(decision.binding.scope, requirement.scope) && decision.digest === decisionDigest(decision) && (checkoutRoot ? verifyDecisionContentAtRoot(checkoutRoot, decision.binding).ok : decision.binding.contentRefs.every((reference) => reference.kind !== "file")));
|
|
59907
59933
|
var applicableRequirementDecision = (task, workspace, requirement, checkoutRoot) => task.decisions.filter(({ data, provenance }) => provenance.kind !== "imported" && data.purpose !== "limitation" && (data.response === "approved" || data.response === "stated") && data.revoked === null && data.binding.taskId === task.id && data.binding.workspaceId === workspace.id && data.requirementIds.includes(requirement.id) && scopeCovers2(data.binding.scope, requirement.scope) && data.digest === decisionDigest(data) && (checkoutRoot ? verifyDecisionContentAtRoot(checkoutRoot, data.binding).ok : data.binding.contentRefs.every((reference) => reference.kind !== "file"))).map(({ id }) => ({ id }));
|
|
59908
59934
|
var evidenceMatchesRequirement = (kind, evidenceKind, dimension, ruleId) => {
|
|
@@ -60255,6 +60281,11 @@ var exportDigest = (bundle) => sha256({
|
|
|
60255
60281
|
});
|
|
60256
60282
|
// packages/workit-core/src/core/external-action.ts
|
|
60257
60283
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
60284
|
+
var chainStepSchema = union2([
|
|
60285
|
+
string2().min(1),
|
|
60286
|
+
object({ branch: string2().min(1) }).strict(),
|
|
60287
|
+
object({ pr: literal(true) }).strict()
|
|
60288
|
+
]);
|
|
60258
60289
|
var externalActionSchema = discriminatedUnion("operation", [
|
|
60259
60290
|
object({
|
|
60260
60291
|
operation: literal("git.branch_setup"),
|
|
@@ -60269,7 +60300,7 @@ var externalActionSchema = discriminatedUnion("operation", [
|
|
|
60269
60300
|
operation: literal("git.commit"),
|
|
60270
60301
|
payload: object({
|
|
60271
60302
|
message: string2().min(1).optional(),
|
|
60272
|
-
plan_steps: array(
|
|
60303
|
+
plan_steps: array(chainStepSchema).min(1).max(32).optional(),
|
|
60273
60304
|
plan_branch: string2().min(1).optional()
|
|
60274
60305
|
}).strict()
|
|
60275
60306
|
}).strict(),
|
|
@@ -60367,7 +60398,13 @@ var externalActionDescriptor = (operation, payload) => canonicalJson({
|
|
|
60367
60398
|
payload,
|
|
60368
60399
|
...payload && typeof payload === "object" && !Array.isArray(payload) && "resolved" in payload && payload.resolved && typeof payload.resolved === "object" && Array.isArray(payload.resolved.steps) ? { steps: payload.resolved.steps } : {}
|
|
60369
60400
|
});
|
|
60370
|
-
var
|
|
60401
|
+
var planReservationLength = (operation, descriptorPayload) => {
|
|
60402
|
+
if (operation !== "git.commit")
|
|
60403
|
+
return null;
|
|
60404
|
+
const payload = descriptorPayload ?? {};
|
|
60405
|
+
return Array.isArray(payload.plan_steps) ? payload.plan_steps.length : null;
|
|
60406
|
+
};
|
|
60407
|
+
var externalActionHelp = "Fixed actions: git.branch_setup {action?,sdd_dir?,target_branch(required unless reapply_stash; the working branch to create or switch to),stash?}; git.commit {message?; plan_steps?: (string | {branch:string} | {pr:true})[]; plan_branch?}; git.push {branch?}; hosting.pull_request {title,body?,draft?,target_branch?,babysit?}; hosting.merge {target_branch?,source_branch?}; youtrack.update {issueId,markdown,minutes?}; youtrack.time {issueId,minutes,text?,dateMs?}; youtrack.meeting {issueId,minutes,text}; changelog.apply {entries?,path?,normalize_only?}; context.read {kind: git|pr|youtrack|github_issue|gitlab_issue|changelog|release|affected,range?,issueId?,issueUrl?,issueRef?,mode?,specPath?,planPath?}. context.read is read-only and needs no approval; all other operations require native approval (CLI uses a TTY; caller-unattested MCP cannot mutate).";
|
|
60371
60408
|
var externalActionRef = (host, actor, descriptor) => ({
|
|
60372
60409
|
kind: "host",
|
|
60373
60410
|
host,
|
|
@@ -60381,12 +60418,12 @@ var externalActionState = (store, host, actor, operation) => {
|
|
|
60381
60418
|
if (!workspace.data)
|
|
60382
60419
|
return failure("not_found", "workspace not found");
|
|
60383
60420
|
const candidates = listed.data.flatMap((task) => {
|
|
60384
|
-
if (task.status !== "active" || task.workspaceId !== workspace.data.id
|
|
60421
|
+
if (task.status !== "active" || task.workspaceId !== workspace.data.id)
|
|
60385
60422
|
return [];
|
|
60386
60423
|
return task.decisions.filter((entry) => entry.data.purpose === "action" && entry.data.response === "approved" && entry.data.revoked === null && entry.data.binding.approvedContent === operation).map((entry) => ({ task, entry }));
|
|
60387
60424
|
});
|
|
60388
60425
|
if (candidates.length !== 1)
|
|
60389
|
-
return failure("permission_denied", candidates.length === 0 ? "no approved action is bound to
|
|
60426
|
+
return failure("permission_denied", candidates.length === 0 ? "no approved action is bound to the active task" : "multiple approved actions match the active task");
|
|
60390
60427
|
return success(workspace.data.revision, null, { ...candidates[0], workspace: workspace.data });
|
|
60391
60428
|
};
|
|
60392
60429
|
var priorExternalAction = (store, host, actor, operation, payload) => {
|
|
@@ -60466,8 +60503,6 @@ var approvedPlanCommit = (store, host, actor, message) => {
|
|
|
60466
60503
|
const matches = listed.data.flatMap((task) => {
|
|
60467
60504
|
if (task.status !== "active" || task.workspaceId !== workspace.data.id)
|
|
60468
60505
|
return [];
|
|
60469
|
-
if (task.intent.provenance.session?.kind !== "host" || task.intent.provenance.session.host !== host || task.intent.provenance.session.handle !== actor)
|
|
60470
|
-
return [];
|
|
60471
60506
|
return task.decisions.flatMap((entry) => {
|
|
60472
60507
|
const decision = entry.data;
|
|
60473
60508
|
if (decision.purpose !== "action" || decision.response !== "approved" || decision.revoked !== null)
|
|
@@ -60509,8 +60544,6 @@ var approvedChainStep = (store, host, actor, query) => {
|
|
|
60509
60544
|
const matches = listed.data.flatMap((task) => {
|
|
60510
60545
|
if (task.status !== "active" || task.workspaceId !== workspace.data.id)
|
|
60511
60546
|
return [];
|
|
60512
|
-
if (task.intent.provenance.session?.kind !== "host" || task.intent.provenance.session.host !== host || task.intent.provenance.session.handle !== actor)
|
|
60513
|
-
return [];
|
|
60514
60547
|
return task.decisions.flatMap((entry) => {
|
|
60515
60548
|
const decision = entry.data;
|
|
60516
60549
|
if (decision.purpose !== "action" || decision.response !== "approved" || decision.revoked !== null)
|
|
@@ -60667,7 +60700,7 @@ var branchSetupIntent = (descriptor) => {
|
|
|
60667
60700
|
var approvedBranchSetupIntent = (store, host, actor, operation) => {
|
|
60668
60701
|
const current = branchSetupIntent(operation);
|
|
60669
60702
|
if (!current)
|
|
60670
|
-
return failure("permission_denied", "no approved action is bound to
|
|
60703
|
+
return failure("permission_denied", "no approved action is bound to the active task");
|
|
60671
60704
|
const listed = store.listTasks();
|
|
60672
60705
|
const workspace = store.readWorkspace();
|
|
60673
60706
|
if (!listed.ok || !workspace.ok)
|
|
@@ -60675,7 +60708,7 @@ var approvedBranchSetupIntent = (store, host, actor, operation) => {
|
|
|
60675
60708
|
if (!workspace.data)
|
|
60676
60709
|
return failure("not_found", "workspace not found");
|
|
60677
60710
|
const candidates = listed.data.flatMap((task) => {
|
|
60678
|
-
if (task.status !== "active" || task.workspaceId !== workspace.data.id
|
|
60711
|
+
if (task.status !== "active" || task.workspaceId !== workspace.data.id)
|
|
60679
60712
|
return [];
|
|
60680
60713
|
return task.decisions.filter((entry) => entry.data.purpose === "action" && entry.data.response === "approved" && entry.data.revoked === null).map((entry) => ({ task, entry }));
|
|
60681
60714
|
});
|
|
@@ -60684,7 +60717,7 @@ var approvedBranchSetupIntent = (store, host, actor, operation) => {
|
|
|
60684
60717
|
return intent !== null && intent.target === current.target && intent.base === current.base && intent.remoteBase === current.remoteBase && intent.targetExists === current.targetExists;
|
|
60685
60718
|
});
|
|
60686
60719
|
if (matches.length !== 1)
|
|
60687
|
-
return failure("permission_denied", matches.length === 0 ? "no approved action is bound to
|
|
60720
|
+
return failure("permission_denied", matches.length === 0 ? "no approved action is bound to the active task" : "multiple approved actions match the active task");
|
|
60688
60721
|
return success(workspace.data.revision, null, { ...matches[0], workspace: workspace.data });
|
|
60689
60722
|
};
|
|
60690
60723
|
var priorResolvedDrift = (store, host, actor, operation, payload, currentResolved) => {
|
|
@@ -61222,6 +61255,7 @@ var verifyNativeWorker = (verifier, input, binding) => {
|
|
|
61222
61255
|
expectedWorkspaceRevision: expected.expectedWorkspaceRevision,
|
|
61223
61256
|
state: expected.state,
|
|
61224
61257
|
session: expected.session,
|
|
61258
|
+
report: expected.report ?? null,
|
|
61225
61259
|
provenance: result.data,
|
|
61226
61260
|
...binding
|
|
61227
61261
|
});
|
|
@@ -61232,7 +61266,7 @@ var takeWorker = (token, binding, expected) => {
|
|
|
61232
61266
|
verifiedWorkers.delete(token);
|
|
61233
61267
|
if (!value)
|
|
61234
61268
|
return null;
|
|
61235
|
-
if (value.owner !== binding.owner || value.store !== binding.store || value.root !== binding.root || value.root !== value.store.root || !sameValue(value.caller, binding.caller) || value.taskId !== expected.taskId || value.workerId !== expected.workerId || value.expectedRevision !== expected.expectedRevision || value.expectedWorkspaceRevision !== expected.expectedWorkspaceRevision || value.state !== expected.state || !sameValue(value.session, expected.session))
|
|
61269
|
+
if (value.owner !== binding.owner || value.store !== binding.store || value.root !== binding.root || value.root !== value.store.root || !sameValue(value.caller, binding.caller) || value.taskId !== expected.taskId || value.workerId !== expected.workerId || value.expectedRevision !== expected.expectedRevision || value.expectedWorkspaceRevision !== expected.expectedWorkspaceRevision || value.state !== expected.state || !sameValue(value.session, expected.session) || !sameValue(value.report, expected.report ?? null))
|
|
61236
61270
|
return null;
|
|
61237
61271
|
return value;
|
|
61238
61272
|
};
|
|
@@ -61273,6 +61307,8 @@ var applyWorkerLifecycle = (input) => {
|
|
|
61273
61307
|
return failure("invalid_transition", "worker already has an observed session");
|
|
61274
61308
|
if (notStarted && !["dispatching", "cancelling"].includes(entry.data.state))
|
|
61275
61309
|
return failure("invalid_transition", "worker launch was not claimed");
|
|
61310
|
+
if (input.report && input.state !== "stopped")
|
|
61311
|
+
return failure("invalid_input", "worker reports require a stopped worker");
|
|
61276
61312
|
if ((input.state === "running" || input.state === "cancelling" || input.state === "stopped" && !notStarted) && !input.session)
|
|
61277
61313
|
return failure("invalid_input", "running worker observations require a session");
|
|
61278
61314
|
if (entry.data.session && !sameValue(entry.data.session, input.session))
|
|
@@ -61289,12 +61325,13 @@ var applyWorkerLifecycle = (input) => {
|
|
|
61289
61325
|
data: {
|
|
61290
61326
|
...entry.data,
|
|
61291
61327
|
state: terminalCancel ? "cancelling" : input.state,
|
|
61292
|
-
session: input.session
|
|
61328
|
+
session: input.session,
|
|
61329
|
+
report: entry.data.report ?? input.report ?? null
|
|
61293
61330
|
}
|
|
61294
61331
|
};
|
|
61295
61332
|
const shouldClear = input.state === "stopped" && workspace.data.writer !== null && workspace.data.writer.owner.taskId === task.data.id && workspace.data.writer.owner.workerId === input.workerId;
|
|
61296
61333
|
const shouldUncertain = input.state === "unknown" && workspace.data.writer !== null && workspace.data.writer.owner.taskId === task.data.id && workspace.data.writer.owner.workerId === input.workerId;
|
|
61297
|
-
if (entry.data.state === nextEntry.data.state && sameValue(entry.data.session, input.session) && !shouldClear && !shouldUncertain)
|
|
61334
|
+
if (entry.data.state === nextEntry.data.state && sameValue(entry.data.session, input.session) && sameValue(entry.data.report, nextEntry.data.report) && !shouldClear && !shouldUncertain)
|
|
61298
61335
|
return success(task.data.revision, workspace.data.revision, entry);
|
|
61299
61336
|
const changed = input.store.mutateTaskAndWorkspace({
|
|
61300
61337
|
taskId: task.data.id,
|
|
@@ -61712,14 +61749,30 @@ class WorkitCore {
|
|
|
61712
61749
|
const listed = this.store.listTasks();
|
|
61713
61750
|
if (!listed.ok)
|
|
61714
61751
|
return listed;
|
|
61715
|
-
const
|
|
61716
|
-
|
|
61717
|
-
|
|
61718
|
-
|
|
61719
|
-
|
|
61720
|
-
|
|
61721
|
-
|
|
61722
|
-
|
|
61752
|
+
const status = input.status ?? "open";
|
|
61753
|
+
const limit = input.limit ?? 20;
|
|
61754
|
+
const selected = listed.data.filter((task) => status === "all" ? true : status === "closed" ? task.status === "closed" : task.status !== "closed").sort((left, right) => right.updatedAt.localeCompare(left.updatedAt)).slice(0, limit);
|
|
61755
|
+
if (selected.length === 0)
|
|
61756
|
+
return success(null, null, []);
|
|
61757
|
+
const workspace = this.store.readWorkspace();
|
|
61758
|
+
if (!workspace.ok)
|
|
61759
|
+
return workspace;
|
|
61760
|
+
if (!workspace.data)
|
|
61761
|
+
return failure("not_found", "workspace not found");
|
|
61762
|
+
const tasks = selected.map((task) => ({
|
|
61763
|
+
id: task.id,
|
|
61764
|
+
revision: task.revision,
|
|
61765
|
+
workspaceRevision: workspace.data.revision,
|
|
61766
|
+
createdAt: task.createdAt,
|
|
61767
|
+
updatedAt: task.updatedAt,
|
|
61768
|
+
runtime: task.runtime ?? null,
|
|
61769
|
+
objective: task.intent.data.objective,
|
|
61770
|
+
status: task.status,
|
|
61771
|
+
closure: task.closure,
|
|
61772
|
+
progress: task.progress,
|
|
61773
|
+
writer: task.status === "closed" ? null : workspace.data.writer
|
|
61774
|
+
}));
|
|
61775
|
+
return success(null, null, tasks);
|
|
61723
61776
|
}
|
|
61724
61777
|
case "inspect": {
|
|
61725
61778
|
const task = this.store.readTask(input.taskId);
|
|
@@ -61728,7 +61781,7 @@ class WorkitCore {
|
|
|
61728
61781
|
const helper = this.helperTaskGuard(task.data, true);
|
|
61729
61782
|
if (!helper.ok)
|
|
61730
61783
|
return helper;
|
|
61731
|
-
if (input.view === "summary")
|
|
61784
|
+
if ((input.view ?? "summary") === "summary")
|
|
61732
61785
|
return this.summary(task.data);
|
|
61733
61786
|
return this.view(task.data);
|
|
61734
61787
|
}
|
|
@@ -62072,7 +62125,7 @@ class WorkitCore {
|
|
|
62072
62125
|
const evaluations = evaluateEvidence(task.data, current.data);
|
|
62073
62126
|
const verified = evidence.some((entry) => {
|
|
62074
62127
|
const evaluation = evaluations.find((item) => item.evidenceId === entry.id);
|
|
62075
|
-
return findingVerificationPasses(finding.data.candidateId, {
|
|
62128
|
+
return entry.recordedAt >= finding.recordedAt && findingVerificationPasses(finding.data.candidateId, {
|
|
62076
62129
|
kind: entry.data.kind,
|
|
62077
62130
|
candidateId: entry.data.candidateId,
|
|
62078
62131
|
status: evaluation?.status ?? "missing"
|
|
@@ -62152,7 +62205,18 @@ class WorkitCore {
|
|
|
62152
62205
|
if (task.data.status !== "active")
|
|
62153
62206
|
return failure("invalid_transition", "paused or closed tasks cannot assign workers");
|
|
62154
62207
|
if (!bindingCovers(task.data.intent.data.scope, input.assignment.scope))
|
|
62155
|
-
return failure("permission_denied", "worker assignment is outside task scope"
|
|
62208
|
+
return failure("permission_denied", "worker assignment is outside task scope", {
|
|
62209
|
+
fields: [
|
|
62210
|
+
{
|
|
62211
|
+
path: "assignment.scope",
|
|
62212
|
+
reason: `paths ${JSON.stringify(input.assignment.scope.paths)} must be contained by lead paths ${JSON.stringify(task.data.intent.data.scope.paths)}`
|
|
62213
|
+
},
|
|
62214
|
+
{
|
|
62215
|
+
path: "task.intent.scope",
|
|
62216
|
+
reason: `lead paths are ${JSON.stringify(task.data.intent.data.scope.paths)}`
|
|
62217
|
+
}
|
|
62218
|
+
]
|
|
62219
|
+
});
|
|
62156
62220
|
if (input.assignment.decisionIds.some((id) => !task.data.decisions.some((entry) => entry.id === id)))
|
|
62157
62221
|
return failure("invalid_input", "worker assignment references an unknown decision");
|
|
62158
62222
|
if (input.assignment.requirementIds.some((id) => !task.data.policy?.requirements.some((requirement) => requirement.id === id)))
|
|
@@ -62359,7 +62423,15 @@ class WorkitCore {
|
|
|
62359
62423
|
...item,
|
|
62360
62424
|
recordedAt: mutation.now,
|
|
62361
62425
|
provenance: attested.data,
|
|
62362
|
-
data: {
|
|
62426
|
+
data: {
|
|
62427
|
+
...item.data,
|
|
62428
|
+
state: "dispatching",
|
|
62429
|
+
coordinator: {
|
|
62430
|
+
kind: "host",
|
|
62431
|
+
host: this.context.caller.host,
|
|
62432
|
+
handle: this.context.caller.actor
|
|
62433
|
+
}
|
|
62434
|
+
}
|
|
62363
62435
|
} : item)
|
|
62364
62436
|
});
|
|
62365
62437
|
}
|
|
@@ -62435,6 +62507,7 @@ class WorkitCore {
|
|
|
62435
62507
|
expectedWorkspaceRevision: input.expectedWorkspaceRevision,
|
|
62436
62508
|
state: "stopped",
|
|
62437
62509
|
session: null,
|
|
62510
|
+
report: null,
|
|
62438
62511
|
provenance: attested.data,
|
|
62439
62512
|
owner: this.authorityOwner,
|
|
62440
62513
|
store: this.store,
|
|
@@ -62742,10 +62815,12 @@ class WorkitCore {
|
|
|
62742
62815
|
return workspace;
|
|
62743
62816
|
if (!workspace.data)
|
|
62744
62817
|
return failure("not_found", "workspace not found");
|
|
62745
|
-
const
|
|
62818
|
+
const historical = task.status === "closed" ? task.candidates.at(-1) : undefined;
|
|
62819
|
+
const current = historical ? success(null, null, historical) : captureCandidate(this.store.root, task.intent.data.scope, environment());
|
|
62746
62820
|
if (!current.ok)
|
|
62747
62821
|
return current;
|
|
62748
|
-
const
|
|
62822
|
+
const evaluationWorkspace = task.status === "closed" ? { ...workspace.data, writer: null } : workspace.data;
|
|
62823
|
+
const requirements = evaluateRequirements(task, evaluationWorkspace, this.context.capabilities, current.data, this.store.root, this.context.caller);
|
|
62749
62824
|
return success(task.revision, workspace.data.revision, {
|
|
62750
62825
|
id: task.id,
|
|
62751
62826
|
revision: task.revision,
|
|
@@ -62759,7 +62834,7 @@ class WorkitCore {
|
|
|
62759
62834
|
progress: task.progress,
|
|
62760
62835
|
policy: task.policy,
|
|
62761
62836
|
requirements,
|
|
62762
|
-
writer:
|
|
62837
|
+
writer: evaluationWorkspace.writer
|
|
62763
62838
|
});
|
|
62764
62839
|
}
|
|
62765
62840
|
view(task) {
|
|
@@ -62768,13 +62843,15 @@ class WorkitCore {
|
|
|
62768
62843
|
return workspace;
|
|
62769
62844
|
if (!workspace.data)
|
|
62770
62845
|
return failure("not_found", "workspace not found");
|
|
62771
|
-
const
|
|
62846
|
+
const historical = task.status === "closed" ? task.candidates.at(-1) : undefined;
|
|
62847
|
+
const current = historical ? success(null, null, historical) : captureCandidate(this.store.root, task.intent.data.scope, environment());
|
|
62772
62848
|
if (!current.ok)
|
|
62773
62849
|
return current;
|
|
62774
|
-
const
|
|
62850
|
+
const evaluationWorkspace = task.status === "closed" ? { ...workspace.data, writer: null } : workspace.data;
|
|
62851
|
+
const requirements = evaluateRequirements(task, evaluationWorkspace, this.context.capabilities, current.data, this.store.root, this.context.caller);
|
|
62775
62852
|
return success(task.revision, workspace.data.revision, {
|
|
62776
62853
|
task,
|
|
62777
|
-
workspace:
|
|
62854
|
+
workspace: evaluationWorkspace,
|
|
62778
62855
|
capabilities: this.context.capabilities,
|
|
62779
62856
|
requirements,
|
|
62780
62857
|
evidence: evaluateEvidence(task, current.data)
|
|
@@ -62865,8 +62942,6 @@ class WorkitCore {
|
|
|
62865
62942
|
return helper;
|
|
62866
62943
|
if (status === "paused" && task.data.status !== "active" || status === "active" && task.data.status !== "paused")
|
|
62867
62944
|
return failure("invalid_transition", `cannot transition ${task.data.status} to ${status}`);
|
|
62868
|
-
if (status === "active" && input.authorityRefs.length === 0)
|
|
62869
|
-
return failure("permission_denied", "resuming a task requires authority references");
|
|
62870
62945
|
const workspace = this.store.readWorkspace();
|
|
62871
62946
|
if (!workspace.ok)
|
|
62872
62947
|
return workspace;
|
|
@@ -62896,7 +62971,7 @@ class WorkitCore {
|
|
|
62896
62971
|
return failure("needs_input", "imported task requires fresh destination evidence");
|
|
62897
62972
|
if (current.data.blockers.some((blocker) => blocker.dependentAction === "resume" || blocker.reason === "worker state requires reconciliation"))
|
|
62898
62973
|
return failure("recovery_required", "imported task requires resume reconciliation");
|
|
62899
|
-
if (!validResumeApproval(task.data, workspace.data, input.authorityRefs, this.context))
|
|
62974
|
+
if (!validResumeApproval(task.data, workspace.data, input.authorityRefs ?? [], this.context))
|
|
62900
62975
|
return failure("permission_denied", "imported resume requires native destination approval");
|
|
62901
62976
|
resumeCandidate = current.data.candidate;
|
|
62902
62977
|
}
|
|
@@ -63026,7 +63101,7 @@ class WorkitCore {
|
|
|
63026
63101
|
task: (value, context) => success(context.revision, null, {
|
|
63027
63102
|
...value,
|
|
63028
63103
|
status: "closed",
|
|
63029
|
-
candidates:
|
|
63104
|
+
candidates: taskForView.candidates,
|
|
63030
63105
|
closure: {
|
|
63031
63106
|
outcome: closure.data.outcome,
|
|
63032
63107
|
at: context.now,
|
|
@@ -64905,7 +64980,7 @@ var readExternalContext = async (root, payload) => {
|
|
|
64905
64980
|
}
|
|
64906
64981
|
}
|
|
64907
64982
|
};
|
|
64908
|
-
var localAction = (operation) => operation === "git.branch_setup" || operation === "git.commit" || operation === "git.push" || operation === "hosting.pull_request" || operation === "changelog.apply";
|
|
64983
|
+
var localAction = (operation) => operation === "git.branch_setup" || operation === "git.commit" || operation === "git.push" || operation === "hosting.pull_request" || operation === "hosting.merge" || operation === "changelog.apply";
|
|
64909
64984
|
var assertLocalExternalActionWriter = (root, caller, paths = ["."]) => {
|
|
64910
64985
|
const store = new TaskStore(root);
|
|
64911
64986
|
const listed = store.listTasks();
|
|
@@ -64916,7 +64991,7 @@ var assertLocalExternalActionWriter = (root, caller, paths = ["."]) => {
|
|
|
64916
64991
|
return workspace;
|
|
64917
64992
|
if (!workspace.data)
|
|
64918
64993
|
return failure("not_found", "workspace not found");
|
|
64919
|
-
const candidates = listed.data.filter((task) => task
|
|
64994
|
+
const candidates = listed.data.filter((task) => currentWriterOwnsTask(task, workspace.data, caller));
|
|
64920
64995
|
if (candidates.length !== 1)
|
|
64921
64996
|
return failure("permission_denied", "local external action requires exactly one active task");
|
|
64922
64997
|
const allowed = assertProductWriteAllowed({
|
|
@@ -64926,7 +65001,7 @@ var assertLocalExternalActionWriter = (root, caller, paths = ["."]) => {
|
|
|
64926
65001
|
paths,
|
|
64927
65002
|
store
|
|
64928
65003
|
});
|
|
64929
|
-
return allowed
|
|
65004
|
+
return allowed;
|
|
64930
65005
|
};
|
|
64931
65006
|
var safePath = (root, value) => {
|
|
64932
65007
|
try {
|
|
@@ -64938,13 +65013,20 @@ var safePath = (root, value) => {
|
|
|
64938
65013
|
var branchCreationBaseline = (root, target, base) => {
|
|
64939
65014
|
const exists = gitValue(root, ["rev-parse", "--verify", "--quiet", `refs/heads/${target}`]) !== null;
|
|
64940
65015
|
if (exists)
|
|
64941
|
-
return {
|
|
65016
|
+
return {
|
|
65017
|
+
base_branch: base,
|
|
65018
|
+
target_exists: true,
|
|
65019
|
+
remote_base: null,
|
|
65020
|
+
target_head: gitValue(root, ["rev-parse", `refs/heads/${target}`])
|
|
65021
|
+
};
|
|
64942
65022
|
const remote = run3(root, ["ls-remote", "origin", `refs/heads/${base}`]);
|
|
64943
65023
|
const sha = remote.exitCode === 0 ? remote.stdout.trim().split(/\s+/)[0] : "";
|
|
65024
|
+
const remoteBase = /^[0-9a-f]{40}$/.test(sha ?? "") ? sha : null;
|
|
64944
65025
|
return {
|
|
64945
65026
|
base_branch: base,
|
|
64946
65027
|
target_exists: false,
|
|
64947
|
-
remote_base:
|
|
65028
|
+
remote_base: remoteBase,
|
|
65029
|
+
target_head: remoteBase
|
|
64948
65030
|
};
|
|
64949
65031
|
};
|
|
64950
65032
|
var shortSha = (value) => typeof value === "string" && value ? value.slice(0, 8) : "unknown";
|
|
@@ -65055,7 +65137,7 @@ var actionProposalQuestion = (request, descriptorPayload) => {
|
|
|
65055
65137
|
var approvedResolvedExternalAction = (content) => {
|
|
65056
65138
|
try {
|
|
65057
65139
|
const value = JSON.parse(content);
|
|
65058
|
-
if (value.operation !== "hosting.pull_request" && value.operation !== "hosting.merge" && value.operation !== "changelog.apply" && value.operation !== "youtrack.update" && value.operation !== "youtrack.time" && value.operation !== "youtrack.meeting")
|
|
65140
|
+
if (value.operation !== "git.branch_setup" && value.operation !== "git.commit" && value.operation !== "git.push" && value.operation !== "hosting.pull_request" && value.operation !== "hosting.merge" && value.operation !== "changelog.apply" && value.operation !== "youtrack.update" && value.operation !== "youtrack.time" && value.operation !== "youtrack.meeting")
|
|
65059
65141
|
return failure("invalid_input", "approved action is not a reconciliable external action");
|
|
65060
65142
|
if (!value.payload || typeof value.payload !== "object")
|
|
65061
65143
|
return failure("invalid_input", "approved action payload is incomplete");
|
|
@@ -65066,18 +65148,24 @@ var approvedResolvedExternalAction = (content) => {
|
|
|
65066
65148
|
if (!request.ok || !resolved || typeof resolved !== "object")
|
|
65067
65149
|
return failure("invalid_input", "approved hosting target is incomplete");
|
|
65068
65150
|
const target = resolved;
|
|
65151
|
+
if (value.operation === "git.commit" && (typeof target.head !== "string" || typeof target.staged !== "string" || typeof payload.message !== "string"))
|
|
65152
|
+
return failure("invalid_input", "approved Git commit target is incomplete");
|
|
65153
|
+
if (value.operation === "git.push" && (typeof target.branch !== "string" || typeof target.commit !== "string" || typeof target.remote !== "string"))
|
|
65154
|
+
return failure("invalid_input", "approved Git push target is incomplete");
|
|
65155
|
+
if (value.operation === "git.branch_setup" && (typeof target.head !== "string" || (payload.action === "reapply_stash" ? typeof target.stash_commit !== "string" : typeof payload.target_branch !== "string" || typeof target.target_head !== "string")))
|
|
65156
|
+
return failure("invalid_input", "approved Git branch target is incomplete");
|
|
65069
65157
|
if (value.operation === "hosting.pull_request" && (typeof target.marker !== "string" || typeof target.source_branch !== "string" || typeof target.source_commit !== "string" || typeof target.remote !== "string" || typeof payload.target_branch !== "string"))
|
|
65070
65158
|
return failure("invalid_input", "approved hosting target is incomplete");
|
|
65071
65159
|
if (value.operation === "hosting.merge" && (typeof target.marker !== "string" || typeof target.source_branch !== "string" || typeof target.source_commit !== "string" || typeof target.remote !== "string" || typeof payload.target_branch !== "string"))
|
|
65072
65160
|
return failure("invalid_input", "approved hosting target is incomplete");
|
|
65073
65161
|
if (value.operation === "changelog.apply" && (typeof target.target !== "string" || typeof target.beforeDigest !== "string" || typeof target.beforeExists !== "boolean" || typeof target.afterDigest !== "string"))
|
|
65074
65162
|
return failure("invalid_input", "approved changelog target is incomplete");
|
|
65075
|
-
if (value.operation !== "hosting.pull_request" && value.operation !== "changelog.apply" && (typeof target.marker !== "string" || typeof target.baseUrl !== "string" || typeof target.issueId !== "string" || !Array.isArray(target.steps)))
|
|
65163
|
+
if (value.operation !== "git.branch_setup" && value.operation !== "git.commit" && value.operation !== "git.push" && value.operation !== "hosting.pull_request" && value.operation !== "hosting.merge" && value.operation !== "changelog.apply" && (typeof target.marker !== "string" || typeof target.baseUrl !== "string" || typeof target.issueId !== "string" || !Array.isArray(target.steps)))
|
|
65076
65164
|
return failure("invalid_input", "approved YouTrack target is incomplete");
|
|
65077
65165
|
return success(null, null, {
|
|
65078
65166
|
request: request.data,
|
|
65079
65167
|
descriptorPayload: value.payload,
|
|
65080
|
-
marker:
|
|
65168
|
+
...typeof target.marker === "string" ? { marker: target.marker } : {}
|
|
65081
65169
|
});
|
|
65082
65170
|
} catch {
|
|
65083
65171
|
return failure("invalid_input", "approved action descriptor is invalid");
|
|
@@ -65103,12 +65191,13 @@ var unknownHostingEvidence = (operation) => failure("external_outcome_unknown",
|
|
|
65103
65191
|
outcome: "unknown"
|
|
65104
65192
|
});
|
|
65105
65193
|
var readHostingAction = async (root, resolved, actionRef) => {
|
|
65106
|
-
|
|
65107
|
-
|
|
65194
|
+
const operation = resolved.request.operation;
|
|
65195
|
+
if (operation !== "hosting.pull_request" && operation !== "hosting.merge" || !resolved.marker)
|
|
65196
|
+
return unknownHostingEvidence(operation);
|
|
65108
65197
|
try {
|
|
65109
65198
|
const cfg = vcsConfig("load", root);
|
|
65110
65199
|
if (!cfg.ok || !cfg.tokenPath || !cfg.provider || cfg.provider !== "github" && cfg.provider !== "gitlab")
|
|
65111
|
-
return unknownHostingEvidence(
|
|
65200
|
+
return unknownHostingEvidence(operation);
|
|
65112
65201
|
const remote = pushRemote(root);
|
|
65113
65202
|
const repo = remote ? remoteRepo(remote) : null;
|
|
65114
65203
|
const approved = resolved.descriptorPayload;
|
|
@@ -65127,7 +65216,7 @@ var readHostingAction = async (root, resolved, actionRef) => {
|
|
|
65127
65216
|
}
|
|
65128
65217
|
})();
|
|
65129
65218
|
if (!repo || typeof branch !== "string" || typeof target !== "string" || typeof sourceCommit !== "string" || typeof approvedRemote !== "string" || !currentIdentity || currentIdentity !== approvedIdentity || repo !== remoteRepo(approvedRemote) || remoteProvider2(approvedRemote) !== null && remoteProvider2(approvedRemote) !== cfg.provider || remoteParts(approvedRemote)?.host !== apiHost)
|
|
65130
|
-
return unknownHostingEvidence(
|
|
65219
|
+
return unknownHostingEvidence(operation);
|
|
65131
65220
|
const token = fs14.readFileSync(cfg.tokenPath, "utf8").trim();
|
|
65132
65221
|
const headers = { Authorization: `Bearer ${token}`, Accept: "application/vnd.github+json" };
|
|
65133
65222
|
const url = cfg.provider === "github" ? `https://api.github.com/repos/${repo}/pulls?state=all&head=${encodeURIComponent(`${repo.split("/")[0]}:${branch}`)}&base=${encodeURIComponent(target)}&per_page=100&page=1` : `${cfg.gitlab?.apiUrl ?? "https://gitlab.com/api/v4"}/projects/${encodeURIComponent(repo)}/merge_requests?state=all&source_branch=${encodeURIComponent(branch)}&target_branch=${encodeURIComponent(target)}&per_page=100&page=1`;
|
|
@@ -65135,14 +65224,14 @@ var readHostingAction = async (root, resolved, actionRef) => {
|
|
|
65135
65224
|
headers: cfg.provider === "gitlab" ? { "PRIVATE-TOKEN": token } : headers
|
|
65136
65225
|
});
|
|
65137
65226
|
if (!response.ok)
|
|
65138
|
-
return unknownHostingEvidence(
|
|
65227
|
+
return unknownHostingEvidence(operation);
|
|
65139
65228
|
const values = await response.json();
|
|
65140
65229
|
if (!Array.isArray(values) || values.length >= 100)
|
|
65141
|
-
return unknownHostingEvidence(
|
|
65230
|
+
return unknownHostingEvidence(operation);
|
|
65142
65231
|
const records = [];
|
|
65143
65232
|
for (const item of values) {
|
|
65144
65233
|
if (!item || typeof item !== "object" || Array.isArray(item))
|
|
65145
|
-
return unknownHostingEvidence(
|
|
65234
|
+
return unknownHostingEvidence(operation);
|
|
65146
65235
|
const record = item;
|
|
65147
65236
|
const body = record.body ?? record.description;
|
|
65148
65237
|
const base = record.base;
|
|
@@ -65154,7 +65243,7 @@ var readHostingAction = async (root, resolved, actionRef) => {
|
|
|
65154
65243
|
const shaValue = cfg.provider === "github" && githubShape ? head.sha : record.sha;
|
|
65155
65244
|
const idValue = record.number ?? record.iid ?? record.id;
|
|
65156
65245
|
if (body !== undefined && body !== null && typeof body !== "string" || (cfg.provider === "github" ? !githubShape : !gitlabShape) || typeof targetValue !== "string" || typeof sourceValue !== "string" || typeof shaValue !== "string" || typeof idValue !== "string" && typeof idValue !== "number")
|
|
65157
|
-
return unknownHostingEvidence(
|
|
65246
|
+
return unknownHostingEvidence(operation);
|
|
65158
65247
|
records.push(record);
|
|
65159
65248
|
}
|
|
65160
65249
|
const matches = records.filter((item) => {
|
|
@@ -65164,15 +65253,23 @@ var readHostingAction = async (root, resolved, actionRef) => {
|
|
|
65164
65253
|
const itemTarget = cfg.provider === "github" ? base?.ref : item.target_branch;
|
|
65165
65254
|
const itemSource = cfg.provider === "github" ? head?.ref : item.source_branch;
|
|
65166
65255
|
const itemSha = cfg.provider === "github" ? head?.sha : item.sha;
|
|
65167
|
-
|
|
65256
|
+
const merged = cfg.provider === "github" ? typeof item.merged_at === "string" : item.state === "merged" || typeof item.merged_at === "string";
|
|
65257
|
+
return (operation === "hosting.merge" ? merged : body.includes(resolved.marker)) && itemTarget === target && itemSource === branch && itemSha === sourceCommit;
|
|
65168
65258
|
});
|
|
65259
|
+
if (operation === "hosting.merge" && records.some((item) => {
|
|
65260
|
+
const base = item.base;
|
|
65261
|
+
const head = item.head;
|
|
65262
|
+
return (cfg.provider === "github" ? base?.ref : item.target_branch) === target && (cfg.provider === "github" ? head?.ref : item.source_branch) === branch && (cfg.provider === "github" ? typeof item.merged_at !== "string" : item.state !== "merged" && typeof item.merged_at !== "string");
|
|
65263
|
+
}))
|
|
65264
|
+
return unknownHostingEvidence(operation);
|
|
65169
65265
|
if (matches.length !== 1)
|
|
65170
|
-
return unknownHostingEvidence(
|
|
65266
|
+
return unknownHostingEvidence(operation);
|
|
65171
65267
|
const item = matches[0];
|
|
65172
65268
|
const id = item.number ?? item.iid ?? item.id;
|
|
65173
65269
|
if (typeof id !== "string" && typeof id !== "number")
|
|
65174
|
-
return unknownHostingEvidence(
|
|
65270
|
+
return unknownHostingEvidence(operation);
|
|
65175
65271
|
const evidenceDigest = sha256({
|
|
65272
|
+
operation,
|
|
65176
65273
|
provider: cfg.provider,
|
|
65177
65274
|
id,
|
|
65178
65275
|
marker: resolved.marker,
|
|
@@ -65193,7 +65290,7 @@ var readHostingAction = async (root, resolved, actionRef) => {
|
|
|
65193
65290
|
data: { provider: cfg.provider, id }
|
|
65194
65291
|
});
|
|
65195
65292
|
} catch {
|
|
65196
|
-
return unknownHostingEvidence(
|
|
65293
|
+
return unknownHostingEvidence(operation);
|
|
65197
65294
|
}
|
|
65198
65295
|
};
|
|
65199
65296
|
var appendMarker = (text, marker) => `${text}${text ? `
|
|
@@ -65283,7 +65380,70 @@ var readYouTrackAction = async (root, resolved, actionRef) => {
|
|
|
65283
65380
|
return unknownHostingEvidence(operation);
|
|
65284
65381
|
}
|
|
65285
65382
|
};
|
|
65286
|
-
var
|
|
65383
|
+
var readLocalAction = async (root, resolved, actionRef) => {
|
|
65384
|
+
const operation = resolved.request.operation;
|
|
65385
|
+
const target = resolved.descriptorPayload.resolved;
|
|
65386
|
+
if (!target)
|
|
65387
|
+
return unknownHostingEvidence(operation);
|
|
65388
|
+
let observed = null;
|
|
65389
|
+
if (operation === "git.commit") {
|
|
65390
|
+
const commit = gitValue(root, ["rev-parse", "HEAD"]);
|
|
65391
|
+
const parent = commit ? gitValue(root, ["rev-parse", `${commit}^`]) : null;
|
|
65392
|
+
const message = commit ? gitValue(root, ["show", "-s", "--format=%B", commit]) : null;
|
|
65393
|
+
const diff = commit && parent ? gitRaw(root, ["diff", "--raw", "-z", "--no-ext-diff", "--no-textconv", parent, commit]) : null;
|
|
65394
|
+
if (commit && parent === target.head && message === resolved.request.payload.message && diff !== null && sha256(diff) === target.staged)
|
|
65395
|
+
observed = { commit, parent, message, staged: target.staged };
|
|
65396
|
+
} else if (operation === "git.push") {
|
|
65397
|
+
const branch = target.branch;
|
|
65398
|
+
const commit = target.commit;
|
|
65399
|
+
const approvedRemote = target.remote;
|
|
65400
|
+
const currentRemote = pushRemote(root);
|
|
65401
|
+
const currentIdentity = currentRemote ? credentialFreeRemote(currentRemote) : null;
|
|
65402
|
+
if (typeof branch === "string" && typeof commit === "string" && typeof approvedRemote === "string" && currentIdentity === approvedRemote) {
|
|
65403
|
+
const remote = run3(root, ["ls-remote", currentRemote, `refs/heads/${branch}`]);
|
|
65404
|
+
const remoteCommit = remote.exitCode === 0 ? remote.stdout.trim().split(/\s+/)[0] : null;
|
|
65405
|
+
if (remoteCommit === commit)
|
|
65406
|
+
observed = { branch, commit, remote: approvedRemote };
|
|
65407
|
+
}
|
|
65408
|
+
} else if (operation === "git.branch_setup") {
|
|
65409
|
+
const targetBranch = resolved.request.payload.target_branch;
|
|
65410
|
+
const sdd = resolved.request.payload.sdd_dir;
|
|
65411
|
+
if (resolved.request.payload.action === "reapply_stash" && typeof sdd === "string") {
|
|
65412
|
+
try {
|
|
65413
|
+
const manifest = JSON.parse(fs14.readFileSync(path28.join(sdd, "manifest.json"), "utf8"));
|
|
65414
|
+
const stashes = gitRaw(root, ["stash", "list", "--format=%H"]);
|
|
65415
|
+
if (typeof target.stash_commit === "string" && manifest.stash_ref === undefined && stashes !== null && !stashes.split(`
|
|
65416
|
+
`).includes(target.stash_commit))
|
|
65417
|
+
observed = { stash_commit: target.stash_commit };
|
|
65418
|
+
} catch {}
|
|
65419
|
+
} else if (typeof targetBranch === "string" && typeof sdd === "string" && gitValue(root, ["branch", "--show-current"]) === targetBranch && typeof target.target_head === "string" && gitValue(root, ["rev-parse", "HEAD"]) === target.target_head) {
|
|
65420
|
+
try {
|
|
65421
|
+
const manifest = JSON.parse(fs14.readFileSync(path28.join(sdd, "manifest.json"), "utf8"));
|
|
65422
|
+
if (manifest.branch === targetBranch)
|
|
65423
|
+
observed = { branch: targetBranch };
|
|
65424
|
+
} catch {}
|
|
65425
|
+
}
|
|
65426
|
+
} else if (operation === "changelog.apply") {
|
|
65427
|
+
const afterDigest = target.afterDigest;
|
|
65428
|
+
const preview = changelogApplyPreview({ ...resolved.request.payload, workspace_root: root });
|
|
65429
|
+
if (!preview.error && typeof afterDigest === "string" && preview.beforeDigest === afterDigest)
|
|
65430
|
+
observed = { target: target.target, afterDigest };
|
|
65431
|
+
}
|
|
65432
|
+
if (!observed)
|
|
65433
|
+
return unknownHostingEvidence(operation);
|
|
65434
|
+
const evidenceDigest = sha256({ operation, observed });
|
|
65435
|
+
return success(null, null, {
|
|
65436
|
+
outcome: "succeeded",
|
|
65437
|
+
evidenceDigest,
|
|
65438
|
+
observation: {
|
|
65439
|
+
kind: "provider_read",
|
|
65440
|
+
actionRef,
|
|
65441
|
+
outcome: "succeeded",
|
|
65442
|
+
evidenceDigest
|
|
65443
|
+
}
|
|
65444
|
+
});
|
|
65445
|
+
};
|
|
65446
|
+
var readExternalAction = async (root, resolved, actionRef) => resolved.request.operation === "git.branch_setup" || resolved.request.operation === "git.commit" || resolved.request.operation === "git.push" || resolved.request.operation === "changelog.apply" ? readLocalAction(root, resolved, actionRef) : resolved.request.operation === "hosting.pull_request" || resolved.request.operation === "hosting.merge" ? readHostingAction(root, resolved, actionRef) : readYouTrackAction(root, resolved, actionRef);
|
|
65287
65447
|
var youTrackBase = () => {
|
|
65288
65448
|
try {
|
|
65289
65449
|
const config = JSON.parse(fs14.readFileSync(youTrackConfigPath(), "utf8"));
|
|
@@ -65341,6 +65501,16 @@ var resolveExternalActionRequest = (root, request, preservedDateMs) => {
|
|
|
65341
65501
|
return failure("storage_error", "current Git commit could not be resolved");
|
|
65342
65502
|
const dirty = Boolean((gitRaw(root, ["status", "--short"]) ?? "").trim());
|
|
65343
65503
|
const creation = action === "reapply_stash" || !target_branch ? { base_branch: policy.defaultTargetBranch } : branchCreationBaseline(root, target_branch, policy.defaultTargetBranch);
|
|
65504
|
+
let stashTarget;
|
|
65505
|
+
if (action === "reapply_stash") {
|
|
65506
|
+
try {
|
|
65507
|
+
const manifest = JSON.parse(fs14.readFileSync(path28.join(sdd_dir, "manifest.json"), "utf8"));
|
|
65508
|
+
const stash_ref = typeof manifest.stash_ref === "string" ? manifest.stash_ref : "";
|
|
65509
|
+
const stash_commit = stash_ref ? gitValue(root, ["rev-parse", stash_ref]) : null;
|
|
65510
|
+
if (stash_ref && stash_commit)
|
|
65511
|
+
stashTarget = { stash_ref, stash_commit };
|
|
65512
|
+
} catch {}
|
|
65513
|
+
}
|
|
65344
65514
|
const normalized = {
|
|
65345
65515
|
operation: request.operation,
|
|
65346
65516
|
payload: {
|
|
@@ -65355,7 +65525,7 @@ var resolveExternalActionRequest = (root, request, preservedDateMs) => {
|
|
|
65355
65525
|
request: normalized,
|
|
65356
65526
|
descriptorPayload: {
|
|
65357
65527
|
...normalized.payload,
|
|
65358
|
-
resolved: { head, dirty, ...creation }
|
|
65528
|
+
resolved: { head, dirty, ...creation, ...stashTarget }
|
|
65359
65529
|
}
|
|
65360
65530
|
});
|
|
65361
65531
|
}
|
|
@@ -65507,7 +65677,7 @@ var resolveExternalActionRequest = (root, request, preservedDateMs) => {
|
|
|
65507
65677
|
outcome: "not_started",
|
|
65508
65678
|
fields: [{ path: "source_branch", reason: "protected branch" }]
|
|
65509
65679
|
});
|
|
65510
|
-
const source_commit = gitValue(root, ["rev-parse", "
|
|
65680
|
+
const source_commit = source_branch ? gitValue(root, ["rev-parse", "--verify", `refs/heads/${source_branch}`]) : null;
|
|
65511
65681
|
const remote = pushRemote(root);
|
|
65512
65682
|
const identity = remote ? credentialFreeRemote(remote) : null;
|
|
65513
65683
|
if (!source_branch || !source_commit || !identity || remoteProvider2(identity) !== null && remoteProvider2(identity) !== String(vcsConfig("load", root).provider).toLowerCase())
|
|
@@ -65795,7 +65965,17 @@ var executeResolvedExternalAction = async (resolved, root, step, caller) => {
|
|
|
65795
65965
|
const workText = fresh.data.descriptorPayload.resolved?.workText;
|
|
65796
65966
|
const beforeDigest = typeof resolvedDetails.resolved?.beforeDigest === "string" ? resolvedDetails.resolved.beforeDigest : undefined;
|
|
65797
65967
|
const beforeExists = typeof resolvedDetails.resolved?.beforeExists === "boolean" ? resolvedDetails.resolved.beforeExists : undefined;
|
|
65798
|
-
|
|
65968
|
+
const result = await executeConcreteExternalAction(fresh.data.request, root, fresh.data.marker, resolvedDate, step, typeof workText === "string" ? workText : undefined, caller, beforeDigest, beforeExists);
|
|
65969
|
+
if (!result.ok && result.code === "external_outcome_unknown" && caller) {
|
|
65970
|
+
const observed = await readLocalAction(root, fresh.data, {
|
|
65971
|
+
kind: "host",
|
|
65972
|
+
host: caller.host,
|
|
65973
|
+
handle: `local-recovery:${fresh.data.request.operation}`
|
|
65974
|
+
});
|
|
65975
|
+
if (observed.ok)
|
|
65976
|
+
return success(null, null, { recovered: true });
|
|
65977
|
+
}
|
|
65978
|
+
return result;
|
|
65799
65979
|
};
|
|
65800
65980
|
|
|
65801
65981
|
// packages/workit-cli/src/task.ts
|
|
@@ -66355,7 +66535,7 @@ async function runActionCommand(argv, deps = {}) {
|
|
|
66355
66535
|
const task = tasks[0];
|
|
66356
66536
|
const prior = externalActionState(store, "workit_cli", actor, descriptor);
|
|
66357
66537
|
const priorRequest = priorExternalAction(store, "workit_cli", actor, normalized.operation, normalized.payload);
|
|
66358
|
-
if (priorRequest.ok && priorRequest.data.entry.data.consumption !== null && priorRequest.data.entry.data.consumption.state !== "uncertain") {
|
|
66538
|
+
if (priorRequest.ok && priorRequest.data.entry.data.consumption !== null && priorRequest.data.entry.data.consumption.state !== "uncertain" && normalized.operation !== "git.commit" && normalized.operation !== "git.push") {
|
|
66359
66539
|
const result = failure("permission_denied", "external action was already settled");
|
|
66360
66540
|
if (json)
|
|
66361
66541
|
jsonResult(outOf(deps), result);
|
|
@@ -66477,6 +66657,16 @@ async function runActionCommand(argv, deps = {}) {
|
|
|
66477
66657
|
nativeAuthority: cliActionAuthority(actor),
|
|
66478
66658
|
workerId: null
|
|
66479
66659
|
});
|
|
66660
|
+
const planCount = planReservationLength(normalized.operation, resolved.data.descriptorPayload);
|
|
66661
|
+
if (planCount !== null) {
|
|
66662
|
+
const bound = standingAutoBinding(core, store, "workit_cli", actor, descriptor);
|
|
66663
|
+
const result = bound ? success(null, null, { plan_commits: planCount }) : failure("storage_error", "standing plan approval could not be recorded");
|
|
66664
|
+
if (json)
|
|
66665
|
+
jsonResult(outOf(deps), result);
|
|
66666
|
+
else
|
|
66667
|
+
printHuman(result, deps);
|
|
66668
|
+
return result.ok ? 0 : 1;
|
|
66669
|
+
}
|
|
66480
66670
|
const runner = nativeExternalActionRunner(root, actor, core);
|
|
66481
66671
|
const result = await runner(descriptor, (step) => executeResolvedExternalAction(resolved.data, root, step, { host: "workit_cli", actor }));
|
|
66482
66672
|
if (json)
|
|
@@ -66531,9 +66721,9 @@ async function runActionCommand(argv, deps = {}) {
|
|
|
66531
66721
|
printHuman(decision, deps);
|
|
66532
66722
|
return 1;
|
|
66533
66723
|
}
|
|
66534
|
-
const
|
|
66535
|
-
if (
|
|
66536
|
-
const result = success(null, null, { plan_commits:
|
|
66724
|
+
const planCount = planReservationLength(normalized.operation, resolved.data.descriptorPayload);
|
|
66725
|
+
if (planCount !== null) {
|
|
66726
|
+
const result = success(null, null, { plan_commits: planCount });
|
|
66537
66727
|
if (json)
|
|
66538
66728
|
jsonResult(outOf(deps), result);
|
|
66539
66729
|
else
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brainervirus/workit-cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"description": "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
|
|
6
6
|
"keywords": [
|
|
@@ -37,9 +37,9 @@
|
|
|
37
37
|
"typecheck": "tsc --noEmit"
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
|
-
"@brainervirus/workit-core": "^1.
|
|
41
|
-
"@brainervirus/workit-cursor": "^1.
|
|
42
|
-
"@brainervirus/workit-opencode": "^1.
|
|
40
|
+
"@brainervirus/workit-core": "^1.2.1",
|
|
41
|
+
"@brainervirus/workit-cursor": "^1.2.1",
|
|
42
|
+
"@brainervirus/workit-opencode": "^1.2.1",
|
|
43
43
|
"@inkjs/ui": "2.0.0",
|
|
44
44
|
"ink": "7.1.1",
|
|
45
45
|
"react": "19.2.8"
|