@brainervirus/workit-cli 1.0.10 → 1.0.11

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.
Files changed (2) hide show
  1. package/dist/index.js +101 -12
  2. package/package.json +4 -4
package/dist/index.js CHANGED
@@ -50928,10 +50928,11 @@ var decisionSchema = object({
50928
50928
  presented: text,
50929
50929
  approvedContent: text,
50930
50930
  displayed: text.optional(),
50931
- contentRefs: array(refSchema)
50931
+ contentRefs: array(refSchema),
50932
+ statedChoice: object({ ref: text, text }).strict().optional()
50932
50933
  }).strict(),
50933
50934
  digest,
50934
- response: _enum(["approved", "rejected"]),
50935
+ response: _enum(["approved", "rejected", "stated"]),
50935
50936
  requirementIds: array(digest),
50936
50937
  revoked: object({ at: utc, reason: text }).strict().nullable(),
50937
50938
  consumption: object({
@@ -58940,7 +58941,7 @@ function evaluateEvidence(task, candidate) {
58940
58941
  }
58941
58942
  var scopeCovers2 = scopeCovers;
58942
58943
  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")));
58943
- var applicableRequirementDecision = (task, workspace, requirement, checkoutRoot) => task.decisions.filter(({ data, provenance }) => provenance.kind !== "imported" && data.purpose !== "limitation" && data.response === "approved" && 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 }));
58944
+ 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 }));
58944
58945
  var evidenceMatchesRequirement = (kind, evidenceKind, dimension) => {
58945
58946
  if (kind !== "passed")
58946
58947
  return false;
@@ -59016,7 +59017,7 @@ function evaluateRequirements(task, workspace, capabilities, candidate, checkout
59016
59017
  status: "satisfied",
59017
59018
  evidenceIds: [],
59018
59019
  decisionIds: decisions.map((decision) => decision.id),
59019
- reason: "an applicable approved decision satisfies the requirement"
59020
+ reason: "an applicable approved or stated decision satisfies the requirement"
59020
59021
  };
59021
59022
  const limitations = requirement.acceptanceAllowed ? applicableDecision2(task, workspace, requirement, checkoutRoot) : [];
59022
59023
  if (limitations.length)
@@ -59500,12 +59501,62 @@ var planCommitBinding = (store, host, actor, operation) => {
59500
59501
  };
59501
59502
  var approvedExternalAction = (store, host, actor, operation) => {
59502
59503
  const selected = externalActionState(store, host, actor, operation);
59503
- if (!selected.ok)
59504
+ if (selected.ok) {
59505
+ if (selected.data.entry.data.consumption !== null)
59506
+ return failure(selected.data.entry.data.consumption.state === "uncertain" ? "external_outcome_unknown" : "permission_denied", selected.data.entry.data.consumption.state === "uncertain" ? "previous external action outcome is unknown" : "external action was already settled");
59504
59507
  return selected;
59505
- if (selected.data.entry.data.consumption !== null)
59506
- return failure(selected.data.entry.data.consumption.state === "uncertain" ? "external_outcome_unknown" : "permission_denied", selected.data.entry.data.consumption.state === "uncertain" ? "previous external action outcome is unknown" : "external action was already settled");
59508
+ }
59509
+ const intent = approvedBranchSetupIntent(store, host, actor, operation);
59510
+ if (intent.ok) {
59511
+ if (intent.data.entry.data.consumption !== null)
59512
+ return failure(intent.data.entry.data.consumption.state === "uncertain" ? "external_outcome_unknown" : "permission_denied", intent.data.entry.data.consumption.state === "uncertain" ? "previous external action outcome is unknown" : "external action was already settled");
59513
+ return intent;
59514
+ }
59507
59515
  return selected;
59508
59516
  };
59517
+ var branchSetupIntent = (descriptor) => {
59518
+ try {
59519
+ const value = JSON.parse(descriptor);
59520
+ if (value.operation !== "git.branch_setup" || !value.payload)
59521
+ return null;
59522
+ const { target_branch, resolved } = value.payload;
59523
+ if (typeof target_branch !== "string" || !target_branch || !resolved)
59524
+ return null;
59525
+ if (typeof resolved.base_branch !== "string" || typeof resolved.target_exists !== "boolean")
59526
+ return null;
59527
+ return {
59528
+ target: target_branch,
59529
+ base: resolved.base_branch,
59530
+ remoteBase: typeof resolved.remote_base === "string" ? resolved.remote_base : null,
59531
+ targetExists: resolved.target_exists
59532
+ };
59533
+ } catch {
59534
+ return null;
59535
+ }
59536
+ };
59537
+ var approvedBranchSetupIntent = (store, host, actor, operation) => {
59538
+ const current = branchSetupIntent(operation);
59539
+ if (!current)
59540
+ return failure("permission_denied", "no approved action is bound to this session");
59541
+ const listed = store.listTasks();
59542
+ const workspace = store.readWorkspace();
59543
+ if (!listed.ok || !workspace.ok)
59544
+ return failure("storage_error", "external action state is unavailable");
59545
+ if (!workspace.data)
59546
+ return failure("not_found", "workspace not found");
59547
+ const candidates = listed.data.flatMap((task) => {
59548
+ if (task.status !== "active" || task.workspaceId !== workspace.data.id || task.intent.provenance.session?.kind !== "host" || task.intent.provenance.session.host !== host || task.intent.provenance.session.handle !== actor)
59549
+ return [];
59550
+ return task.decisions.filter((entry) => entry.data.purpose === "action" && entry.data.response === "approved" && entry.data.revoked === null).map((entry) => ({ task, entry }));
59551
+ });
59552
+ const matches = candidates.filter(({ entry }) => {
59553
+ const intent = branchSetupIntent(entry.data.binding.approvedContent);
59554
+ return intent !== null && intent.target === current.target && intent.base === current.base && intent.remoteBase === current.remoteBase && intent.targetExists === current.targetExists;
59555
+ });
59556
+ if (matches.length !== 1)
59557
+ return failure("permission_denied", matches.length === 0 ? "no approved action is bound to this session" : "multiple approved actions match this session");
59558
+ return success(workspace.data.revision, null, { ...matches[0], workspace: workspace.data });
59559
+ };
59509
59560
  var priorResolvedDrift = (store, host, actor, operation, payload, currentResolved) => {
59510
59561
  const prior = priorExternalAction(store, host, actor, operation, payload);
59511
59562
  if (!prior.ok)
@@ -59519,6 +59570,24 @@ var priorResolvedDrift = (store, host, actor, operation, payload, currentResolve
59519
59570
  }
59520
59571
  if (baseline === undefined || baseline === null)
59521
59572
  return success(null, null, null);
59573
+ if (operation === "git.branch_setup") {
59574
+ const before = branchSetupIntent(prior.data.entry.data.binding.approvedContent);
59575
+ let after = null;
59576
+ try {
59577
+ after = branchSetupIntent(JSON.stringify({
59578
+ operation,
59579
+ payload: { ...payload, resolved: currentResolved }
59580
+ }));
59581
+ } catch {
59582
+ after = null;
59583
+ }
59584
+ if (before && after) {
59585
+ const moved = before.target !== after.target ? "target_branch" : before.base !== after.base ? "base_branch" : before.remoteBase !== after.remoteBase ? "remote_base" : before.targetExists !== after.targetExists ? "target_exists" : null;
59586
+ if (moved === null)
59587
+ return success(null, null, null);
59588
+ return failure("invalid_input", `repository state changed since approval (${moved} moved); show the current state and approve the action again`, { outcome: "not_started", operation });
59589
+ }
59590
+ }
59522
59591
  if (canonicalJson(baseline) === canonicalJson(currentResolved))
59523
59592
  return success(null, null, null);
59524
59593
  return failure("invalid_input", "repository state changed since approval; show the current state and approve the action again", { outcome: "not_started", operation });
@@ -60774,7 +60843,12 @@ class WorkitCore {
60774
60843
  const input = parsed.data;
60775
60844
  if (nativeRequired && input.action !== "record")
60776
60845
  return failure("permission_denied", "native observation is only valid for recording decisions");
60777
- if (nativeRequired && nativeObservation === undefined)
60846
+ const stated = input.action === "record" && input.response === "stated";
60847
+ if (stated && input.purpose === "action")
60848
+ return failure("permission_denied", "stated choices cannot authorize mutating actions");
60849
+ if (stated && !input.binding?.statedChoice)
60850
+ return failure("invalid_input", "stated choices require binding.statedChoice");
60851
+ if (nativeRequired && nativeObservation === undefined && !stated)
60778
60852
  return failure("permission_denied", "native decision observation is required");
60779
60853
  const task = this.store.readTask(input.taskId);
60780
60854
  if (!task.ok)
@@ -60807,7 +60881,7 @@ class WorkitCore {
60807
60881
  consumption: null
60808
60882
  };
60809
60883
  const data = { ...base, digest: decisionDigest(base) };
60810
- const native = nativeRequired ? verifyNativeDecision(this.context.nativeAuthority, {
60884
+ const native = nativeRequired && !stated ? verifyNativeDecision(this.context.nativeAuthority, {
60811
60885
  observation: nativeObservation,
60812
60886
  expected: {
60813
60887
  taskId: task.data.id,
@@ -64288,13 +64362,20 @@ var actionProposalQuestion = (request, descriptorPayload) => {
64288
64362
  approvedText: "Reapply the recorded stash."
64289
64363
  };
64290
64364
  const target = String(payload.target_branch ?? "");
64365
+ const stashes = payload.stash === "yes" && resolved.dirty === true;
64291
64366
  if (resolved.target_exists === true)
64292
- return {
64367
+ return stashes ? {
64368
+ presented: `Workit decision: action — Stash the dirty working tree and switch to branch \`${target}\`?`,
64369
+ approvedText: `Stash and switch to \`${target}\`.`
64370
+ } : {
64293
64371
  presented: `Workit decision: action — Switch to branch \`${target}\`?`,
64294
64372
  approvedText: `Switch to \`${target}\`.`
64295
64373
  };
64296
64374
  const base = String(resolved.base_branch ?? "the base branch");
64297
- return {
64375
+ return stashes ? {
64376
+ presented: `Workit decision: action — Stash the dirty working tree and create branch \`${target}\` from \`${base}\` (currently ${shortSha(resolved.remote_base)})?`,
64377
+ approvedText: `Stash and create \`${target}\` from \`${base}\` at ${shortSha(resolved.remote_base)}.`
64378
+ } : {
64298
64379
  presented: `Workit decision: action — Create branch \`${target}\` from \`${base}\` (currently ${shortSha(resolved.remote_base)})?`,
64299
64380
  approvedText: `Create \`${target}\` from \`${base}\` at ${shortSha(resolved.remote_base)}.`
64300
64381
  };
@@ -65486,7 +65567,7 @@ async function runActionCommand(argv, deps = {}) {
65486
65567
  return 2;
65487
65568
  }
65488
65569
  const root = deps.root ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? deps.cwd ?? process.cwd();
65489
- const resolved = resolveExternalActionRequest(root, parsed.data);
65570
+ let resolved = resolveExternalActionRequest(root, parsed.data);
65490
65571
  if (!resolved.ok) {
65491
65572
  if (json)
65492
65573
  jsonResult(outOf(deps), resolved);
@@ -65494,6 +65575,14 @@ async function runActionCommand(argv, deps = {}) {
65494
65575
  printHuman(resolved, deps);
65495
65576
  return 2;
65496
65577
  }
65578
+ if (resolved.data.request.operation === "git.branch_setup" && resolved.data.descriptorPayload.resolved?.dirty === true && resolved.data.descriptorPayload.stash !== "yes") {
65579
+ const upgraded = resolveExternalActionRequest(root, {
65580
+ ...parsed.data,
65581
+ payload: { ...parsed.data.payload, stash: "yes" }
65582
+ });
65583
+ if (upgraded.ok)
65584
+ resolved = upgraded;
65585
+ }
65497
65586
  const normalized = resolved.data.request;
65498
65587
  const descriptor = externalActionDescriptor(normalized.operation, resolved.data.descriptorPayload);
65499
65588
  if (preview) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cli",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
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.0.10",
41
- "@brainervirus/workit-cursor": "^1.0.10",
42
- "@brainervirus/workit-opencode": "^1.0.10",
40
+ "@brainervirus/workit-core": "^1.0.11",
41
+ "@brainervirus/workit-cursor": "^1.0.11",
42
+ "@brainervirus/workit-opencode": "^1.0.11",
43
43
  "@inkjs/ui": "2.0.0",
44
44
  "ink": "7.1.1",
45
45
  "react": "19.2.8"