@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 +3 -2
- package/dist/workit.js +119 -13
- package/package.json +1 -1
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 (
|
|
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
|
-
|
|
11334
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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" ?
|
|
18055
|
+
const route = typeof command === "string" ? shouldDenyShellRoute(ctx.cwd, command) : null;
|
|
17950
18056
|
if (route)
|
|
17951
18057
|
return {
|
|
17952
18058
|
block: true,
|