@brainervirus/workit-pi 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.
package/dist/worker.js CHANGED
@@ -7554,10 +7554,11 @@ var decisionSchema = object({
7554
7554
  presented: text,
7555
7555
  approvedContent: text,
7556
7556
  displayed: text.optional(),
7557
- contentRefs: array(refSchema)
7557
+ contentRefs: array(refSchema),
7558
+ statedChoice: object({ ref: text, text }).strict().optional()
7558
7559
  }).strict(),
7559
7560
  digest,
7560
- response: _enum(["approved", "rejected"]),
7561
+ response: _enum(["approved", "rejected", "stated"]),
7561
7562
  requirementIds: array(digest),
7562
7563
  revoked: object({ at: utc, reason: text }).strict().nullable(),
7563
7564
  consumption: object({
package/dist/workit.js CHANGED
@@ -7797,10 +7797,11 @@ var decisionSchema = object({
7797
7797
  presented: text,
7798
7798
  approvedContent: text,
7799
7799
  displayed: text.optional(),
7800
- contentRefs: array(refSchema)
7800
+ contentRefs: array(refSchema),
7801
+ statedChoice: object({ ref: text, text }).strict().optional()
7801
7802
  }).strict(),
7802
7803
  digest,
7803
- response: _enum(["approved", "rejected"]),
7804
+ response: _enum(["approved", "rejected", "stated"]),
7804
7805
  requirementIds: array(digest),
7805
7806
  revoked: object({ at: utc, reason: text }).strict().nullable(),
7806
7807
  consumption: object({
@@ -10673,7 +10674,7 @@ function evaluateEvidence(task, candidate) {
10673
10674
  }
10674
10675
  var scopeCovers2 = scopeCovers;
10675
10676
  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")));
10676
- 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 }));
10677
+ 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 }));
10677
10678
  var evidenceMatchesRequirement = (kind, evidenceKind, dimension) => {
10678
10679
  if (kind !== "passed")
10679
10680
  return false;
@@ -10749,7 +10750,7 @@ function evaluateRequirements(task, workspace, capabilities, candidate, checkout
10749
10750
  status: "satisfied",
10750
10751
  evidenceIds: [],
10751
10752
  decisionIds: decisions.map((decision) => decision.id),
10752
- reason: "an applicable approved decision satisfies the requirement"
10753
+ reason: "an applicable approved or stated decision satisfies the requirement"
10753
10754
  };
10754
10755
  const limitations = requirement.acceptanceAllowed ? applicableDecision2(task, workspace, requirement, checkoutRoot) : [];
10755
10756
  if (limitations.length)
@@ -11082,6 +11083,23 @@ function shellRouteIntent(command) {
11082
11083
  }
11083
11084
  return null;
11084
11085
  }
11086
+ function hasLiveWorkitTask(dir) {
11087
+ try {
11088
+ if (typeof dir !== "string" || dir === "")
11089
+ return false;
11090
+ const listed = new TaskStore(dir).listTasks();
11091
+ if (!listed.ok)
11092
+ return false;
11093
+ return listed.data.some((task) => task.status === "active" || task.status === "paused");
11094
+ } catch {
11095
+ return false;
11096
+ }
11097
+ }
11098
+ function shouldDenyShellRoute(dir, command) {
11099
+ if (!hasLiveWorkitTask(dir))
11100
+ return null;
11101
+ return shellRouteIntent(command);
11102
+ }
11085
11103
  // packages/workit-core/src/core/external-action.ts
11086
11104
  import { execFileSync } from "node:child_process";
11087
11105
  var externalActionSchema = discriminatedUnion("operation", [
@@ -11328,12 +11346,62 @@ var planCommitBinding = (store, host, actor, operation) => {
11328
11346
  };
11329
11347
  var approvedExternalAction = (store, host, actor, operation) => {
11330
11348
  const selected = externalActionState(store, host, actor, operation);
11331
- if (!selected.ok)
11349
+ if (selected.ok) {
11350
+ if (selected.data.entry.data.consumption !== null)
11351
+ 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");
11332
11352
  return selected;
11333
- if (selected.data.entry.data.consumption !== null)
11334
- 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");
11353
+ }
11354
+ const intent = approvedBranchSetupIntent(store, host, actor, operation);
11355
+ if (intent.ok) {
11356
+ if (intent.data.entry.data.consumption !== null)
11357
+ 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");
11358
+ return intent;
11359
+ }
11335
11360
  return selected;
11336
11361
  };
11362
+ var branchSetupIntent = (descriptor) => {
11363
+ try {
11364
+ const value = JSON.parse(descriptor);
11365
+ if (value.operation !== "git.branch_setup" || !value.payload)
11366
+ return null;
11367
+ const { target_branch, resolved } = value.payload;
11368
+ if (typeof target_branch !== "string" || !target_branch || !resolved)
11369
+ return null;
11370
+ if (typeof resolved.base_branch !== "string" || typeof resolved.target_exists !== "boolean")
11371
+ return null;
11372
+ return {
11373
+ target: target_branch,
11374
+ base: resolved.base_branch,
11375
+ remoteBase: typeof resolved.remote_base === "string" ? resolved.remote_base : null,
11376
+ targetExists: resolved.target_exists
11377
+ };
11378
+ } catch {
11379
+ return null;
11380
+ }
11381
+ };
11382
+ var approvedBranchSetupIntent = (store, host, actor, operation) => {
11383
+ const current = branchSetupIntent(operation);
11384
+ if (!current)
11385
+ return failure("permission_denied", "no approved action is bound to this session");
11386
+ const listed = store.listTasks();
11387
+ const workspace = store.readWorkspace();
11388
+ if (!listed.ok || !workspace.ok)
11389
+ return failure("storage_error", "external action state is unavailable");
11390
+ if (!workspace.data)
11391
+ return failure("not_found", "workspace not found");
11392
+ const candidates = listed.data.flatMap((task) => {
11393
+ 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)
11394
+ return [];
11395
+ return task.decisions.filter((entry) => entry.data.purpose === "action" && entry.data.response === "approved" && entry.data.revoked === null).map((entry) => ({ task, entry }));
11396
+ });
11397
+ const matches = candidates.filter(({ entry }) => {
11398
+ const intent = branchSetupIntent(entry.data.binding.approvedContent);
11399
+ return intent !== null && intent.target === current.target && intent.base === current.base && intent.remoteBase === current.remoteBase && intent.targetExists === current.targetExists;
11400
+ });
11401
+ if (matches.length !== 1)
11402
+ return failure("permission_denied", matches.length === 0 ? "no approved action is bound to this session" : "multiple approved actions match this session");
11403
+ return success(workspace.data.revision, null, { ...matches[0], workspace: workspace.data });
11404
+ };
11337
11405
  var priorResolvedDrift = (store, host, actor, operation, payload, currentResolved) => {
11338
11406
  const prior = priorExternalAction(store, host, actor, operation, payload);
11339
11407
  if (!prior.ok)
@@ -11347,6 +11415,24 @@ var priorResolvedDrift = (store, host, actor, operation, payload, currentResolve
11347
11415
  }
11348
11416
  if (baseline === undefined || baseline === null)
11349
11417
  return success(null, null, null);
11418
+ if (operation === "git.branch_setup") {
11419
+ const before = branchSetupIntent(prior.data.entry.data.binding.approvedContent);
11420
+ let after = null;
11421
+ try {
11422
+ after = branchSetupIntent(JSON.stringify({
11423
+ operation,
11424
+ payload: { ...payload, resolved: currentResolved }
11425
+ }));
11426
+ } catch {
11427
+ after = null;
11428
+ }
11429
+ if (before && after) {
11430
+ 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;
11431
+ if (moved === null)
11432
+ return success(null, null, null);
11433
+ return failure("invalid_input", `repository state changed since approval (${moved} moved); show the current state and approve the action again`, { outcome: "not_started", operation });
11434
+ }
11435
+ }
11350
11436
  if (canonicalJson(baseline) === canonicalJson(currentResolved))
11351
11437
  return success(null, null, null);
11352
11438
  return failure("invalid_input", "repository state changed since approval; show the current state and approve the action again", { outcome: "not_started", operation });
@@ -12621,7 +12707,12 @@ class WorkitCore {
12621
12707
  const input = parsed.data;
12622
12708
  if (nativeRequired && input.action !== "record")
12623
12709
  return failure("permission_denied", "native observation is only valid for recording decisions");
12624
- if (nativeRequired && nativeObservation === undefined)
12710
+ const stated = input.action === "record" && input.response === "stated";
12711
+ if (stated && input.purpose === "action")
12712
+ return failure("permission_denied", "stated choices cannot authorize mutating actions");
12713
+ if (stated && !input.binding?.statedChoice)
12714
+ return failure("invalid_input", "stated choices require binding.statedChoice");
12715
+ if (nativeRequired && nativeObservation === undefined && !stated)
12625
12716
  return failure("permission_denied", "native decision observation is required");
12626
12717
  const task = this.store.readTask(input.taskId);
12627
12718
  if (!task.ok)
@@ -12654,7 +12745,7 @@ class WorkitCore {
12654
12745
  consumption: null
12655
12746
  };
12656
12747
  const data = { ...base, digest: decisionDigest(base) };
12657
- const native = nativeRequired ? verifyNativeDecision(this.context.nativeAuthority, {
12748
+ const native = nativeRequired && !stated ? verifyNativeDecision(this.context.nativeAuthority, {
12658
12749
  observation: nativeObservation,
12659
12750
  expected: {
12660
12751
  taskId: task.data.id,
@@ -16862,13 +16953,20 @@ var actionProposalQuestion = (request, descriptorPayload) => {
16862
16953
  approvedText: "Reapply the recorded stash."
16863
16954
  };
16864
16955
  const target = String(payload.target_branch ?? "");
16956
+ const stashes = payload.stash === "yes" && resolved.dirty === true;
16865
16957
  if (resolved.target_exists === true)
16866
- return {
16958
+ return stashes ? {
16959
+ presented: `Workit decision: action — Stash the dirty working tree and switch to branch \`${target}\`?`,
16960
+ approvedText: `Stash and switch to \`${target}\`.`
16961
+ } : {
16867
16962
  presented: `Workit decision: action — Switch to branch \`${target}\`?`,
16868
16963
  approvedText: `Switch to \`${target}\`.`
16869
16964
  };
16870
16965
  const base = String(resolved.base_branch ?? "the base branch");
16871
- return {
16966
+ return stashes ? {
16967
+ presented: `Workit decision: action — Stash the dirty working tree and create branch \`${target}\` from \`${base}\` (currently ${shortSha(resolved.remote_base)})?`,
16968
+ approvedText: `Stash and create \`${target}\` from \`${base}\` at ${shortSha(resolved.remote_base)}.`
16969
+ } : {
16872
16970
  presented: `Workit decision: action — Create branch \`${target}\` from \`${base}\` (currently ${shortSha(resolved.remote_base)})?`,
16873
16971
  approvedText: `Create \`${target}\` from \`${base}\` at ${shortSha(resolved.remote_base)}.`
16874
16972
  };
@@ -17810,9 +17908,17 @@ var registerWorkitTools = (pi, options = {}) => {
17810
17908
  if (!parsed.ok)
17811
17909
  return output(parsed);
17812
17910
  const context = piContext(ctx);
17813
- const resolved = resolveExternalActionRequest(ctx.cwd, parsed.data);
17911
+ let resolved = resolveExternalActionRequest(ctx.cwd, parsed.data);
17814
17912
  if (!resolved.ok)
17815
17913
  return output(resolved);
17914
+ if (resolved.data.request.operation === "git.branch_setup" && resolved.data.descriptorPayload.resolved?.dirty === true && resolved.data.descriptorPayload.stash !== "yes") {
17915
+ const upgraded = resolveExternalActionRequest(ctx.cwd, {
17916
+ ...parsed.data,
17917
+ payload: { ...parsed.data.payload, stash: "yes" }
17918
+ });
17919
+ if (upgraded.ok)
17920
+ resolved = upgraded;
17921
+ }
17816
17922
  if (resolved.data.request.operation === "context.read")
17817
17923
  return output(await executeResolvedExternalAction(resolved.data, ctx.cwd));
17818
17924
  if (!ctx.isProjectTrusted())
@@ -17946,7 +18052,7 @@ var registerWorkitTools = (pi, options = {}) => {
17946
18052
  var enforceNativeWriter = (event, ctx) => {
17947
18053
  if (event.toolName === "bash") {
17948
18054
  const command = event.input?.command;
17949
- const route = typeof command === "string" ? shellRouteIntent(command) : null;
18055
+ const route = typeof command === "string" ? shouldDenyShellRoute(ctx.cwd, command) : null;
17950
18056
  if (route)
17951
18057
  return {
17952
18058
  block: true,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-pi",
3
- "version": "1.0.10",
3
+ "version": "1.0.11",
4
4
  "description": "Workit native extension for Pi — tools, method skills, and session continuity",
5
5
  "keywords": [
6
6
  "agentic-coding",