@sema-agent/core 7.8.0 → 7.9.0

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 (73) hide show
  1. package/CHANGELOG.md +52 -1
  2. package/dist/agents/subagent.d.ts +1 -1
  3. package/dist/core/ask-origin.d.ts +12 -1
  4. package/dist/core/ask-origin.js +5 -1
  5. package/dist/core/checkpoint-store.d.ts +34 -28
  6. package/dist/core/gate-lanes.js +49 -23
  7. package/dist/core/gate-outcome.d.ts +8 -4
  8. package/dist/core/gate-outcome.js +2 -1
  9. package/dist/core/hooks.d.ts +56 -31
  10. package/dist/core/permission-rule-consent.d.ts +29 -36
  11. package/dist/core/permission-rule-consent.js +110 -60
  12. package/dist/core/permission-rule-model.d.ts +254 -55
  13. package/dist/core/permission-rule-model.js +323 -43
  14. package/dist/core/permission-rule-org.d.ts +9 -8
  15. package/dist/core/permission-rule-org.js +6 -15
  16. package/dist/core/permission-rule-provider.d.ts +10 -6
  17. package/dist/core/permission-rule-provider.js +12 -8
  18. package/dist/core/permission-rule-session.d.ts +7 -6
  19. package/dist/core/permission-rule-session.js +29 -10
  20. package/dist/core/permission-rule-store.d.ts +40 -18
  21. package/dist/core/permission-rule-store.js +68 -42
  22. package/dist/core/permission-rule-sync.d.ts +9 -3
  23. package/dist/core/permission-rule-sync.js +29 -25
  24. package/dist/core/permission-rule-syntax.d.ts +30 -0
  25. package/dist/core/permission-rule-syntax.js +44 -0
  26. package/dist/core/permission-rules.d.ts +55 -33
  27. package/dist/core/permission-rules.js +65 -55
  28. package/dist/core/persisted-rule-arms.d.ts +56 -0
  29. package/dist/core/persisted-rule-arms.js +48 -0
  30. package/dist/core/runner/contracts.d.ts +21 -2
  31. package/dist/core/runner/permission-rule-lanes.d.ts +33 -26
  32. package/dist/core/runner/permission-rule-lanes.js +27 -21
  33. package/dist/core/runner/prepare-gate-stations.js +1 -1
  34. package/dist/core/runner/prepare-safety-scan.js +8 -2
  35. package/dist/core/runner/prepare-task.js +1 -1
  36. package/dist/core/runner/resume-admission.d.ts +53 -0
  37. package/dist/core/runner/resume-admission.js +83 -0
  38. package/dist/core/runner/resume-apply.d.ts +50 -0
  39. package/dist/core/runner/resume-apply.js +184 -0
  40. package/dist/core/runner/resume-checkpoint-screen.d.ts +18 -0
  41. package/dist/core/runner/resume-checkpoint-screen.js +108 -0
  42. package/dist/core/runner/resume-claim.d.ts +32 -0
  43. package/dist/core/runner/resume-claim.js +27 -0
  44. package/dist/core/runner/resume-internals-and-config.d.ts +33 -0
  45. package/dist/core/runner/resume-internals-and-config.js +50 -0
  46. package/dist/core/runner/resume-policy-outcome.d.ts +31 -0
  47. package/dist/core/runner/resume-policy-outcome.js +127 -0
  48. package/dist/core/runner/resume-preflight.d.ts +40 -0
  49. package/dist/core/runner/resume-preflight.js +122 -0
  50. package/dist/core/runner/resume-review-outcome.d.ts +30 -0
  51. package/dist/core/runner/resume-review-outcome.js +88 -0
  52. package/dist/core/runner/run-harness-handlers.js +1 -1
  53. package/dist/core/runner/runtask.d.ts +20 -0
  54. package/dist/core/runner/runtask.js +85 -734
  55. package/dist/core/runner/tool-end-body.d.ts +12 -5
  56. package/dist/core/runner/tool-end-body.js +5 -5
  57. package/dist/core/runner/tool-output-projection.d.ts +9 -6
  58. package/dist/core/runner/tool-output-projection.js +1 -18
  59. package/dist/core/runner/turn-attachments.d.ts +2 -2
  60. package/dist/core/store-contracts/permission-rule-sync-contract.js +29 -10
  61. package/dist/core/tool-roster.d.ts +9 -0
  62. package/dist/core/tool-roster.js +15 -5
  63. package/dist/index.d.ts +2 -2
  64. package/dist/index.js +2 -2
  65. package/dist/stores/file/checkpoint-store.js +1 -1
  66. package/dist/stores/file/permission-rule-store.d.ts +28 -23
  67. package/dist/stores/file/permission-rule-store.js +64 -16
  68. package/dist/tools/fs/bash-readonly-classifier.d.ts +1 -1
  69. package/dist/tools/fs/fs-pdf.d.ts +1 -1
  70. package/dist/tools/fs/notebook.d.ts +1 -1
  71. package/dist/tools/fs/safety.d.ts +1 -1
  72. package/package.json +1 -1
  73. package/test/export-surface.snapshot.json +43 -11
@@ -0,0 +1,88 @@
1
+ import { CheckpointError } from "../checkpoint-store.js";
2
+ import { isGateKind, PAUSE_REGISTRY, resumeGateMatches } from "../pause-registry.js";
3
+ import { sanitizeUntrustedText } from "../untrusted-text.js";
4
+ import { assertOutcomeText, describeSuppliedValue } from "./decide-continuation.js";
5
+ export function resumeReviewOutcome(input) {
6
+ const { cp, outcome, outcomeGate, wakeMessage } = input;
7
+ const gateMatch = isGateKind(cp.gate.kind) && resumeGateMatches(cp.gate.kind, outcomeGate);
8
+ if (!gateMatch) {
9
+ throw new CheckpointError("checkpoint.gate_mismatch", `resume outcome (gate "${describeSuppliedValue(outcomeGate)}") does not match checkpoint gate "${cp.gate.kind}" — resume serves ${Object.entries(PAUSE_REGISTRY)
10
+ .filter(([, row]) => !row.terminal)
11
+ .map(([k, row]) => `${k}/${row.resume}`)
12
+ .join(", ")}`);
13
+ }
14
+ let plainReviewOutcome;
15
+ if (cp.gate.kind === "plan_review") {
16
+ const decide = outcome;
17
+ const decision = decide.decision;
18
+ const editedPlan = decide.editedPlan;
19
+ const reason = decide.reason;
20
+ if (decision !== "approve" && decision !== "edit" && decision !== "reject") {
21
+ throw new CheckpointError("checkpoint.invalid_outcome", `resume decision "${describeSuppliedValue(decision)}" is outside the plan_review domain — a plan review is exactly "approve", "edit" or "reject"; refusing pre-CAS, the checkpoint stays pending`);
22
+ }
23
+ assertOutcomeText(editedPlan, "editedPlan");
24
+ assertOutcomeText(reason, "reason");
25
+ plainReviewOutcome = {
26
+ gate: "plan_review",
27
+ decision,
28
+ ...(editedPlan !== undefined ? { editedPlan } : {}),
29
+ ...(reason !== undefined ? { reason } : {}),
30
+ };
31
+ }
32
+ else if (cp.gate.kind === "needs_review") {
33
+ const decide = outcome;
34
+ const decision = decide.decision;
35
+ const reason = decide.reason;
36
+ if (decision !== "approve" && decision !== "reject") {
37
+ throw new CheckpointError("checkpoint.invalid_outcome", `resume decision "${describeSuppliedValue(decision)}" is outside the dry_run_review domain — a dry-run review is exactly "approve" or "reject"; refusing pre-CAS, the checkpoint stays pending`);
38
+ }
39
+ assertOutcomeText(reason, "reason");
40
+ plainReviewOutcome = {
41
+ gate: "dry_run_review",
42
+ decision,
43
+ ...(reason !== undefined ? { reason } : {}),
44
+ };
45
+ }
46
+ if (plainReviewOutcome !== undefined) {
47
+ const reason = plainReviewOutcome.reason;
48
+ if (plainReviewOutcome.decision === "reject" && reason && sanitizeUntrustedText(reason) !== reason) {
49
+ throw new CheckpointError("checkpoint.invalid_outcome", "resume deny/reject reason must not contain a </system-reminder> tag");
50
+ }
51
+ const capturedPlan = plainReviewOutcome.gate === "plan_review" ? plainReviewOutcome.editedPlan : undefined;
52
+ if (plainReviewOutcome.decision === "edit" &&
53
+ capturedPlan &&
54
+ sanitizeUntrustedText(capturedPlan) !== capturedPlan) {
55
+ throw new CheckpointError("checkpoint.invalid_outcome", "resume editedPlan must not contain a </system-reminder> tag");
56
+ }
57
+ if (cp.reopenReason === "env_failed") {
58
+ const winner = cp.resolvedOutcome;
59
+ if (winner === undefined) {
60
+ throw new CheckpointError("checkpoint.reopen_revote", "review checkpoint was reopened after an env-restore failure (env_failed) but carries no persisted winner to replay — refusing to resume (inconsistent row, fail-closed)");
61
+ }
62
+ if (winner.decision !== plainReviewOutcome.decision) {
63
+ throw new CheckpointError("checkpoint.reopen_revote", `an env_failed reopen replays the ALREADY-RECORDED review decision ("${winner.decision}") — refusing a re-vote with a different decision ("${plainReviewOutcome.decision}")`);
64
+ }
65
+ if (winner.updatedInput !== capturedPlan) {
66
+ throw new CheckpointError("checkpoint.reopen_revote", "an env_failed reopen replays the ALREADY-RECORDED review decision — refusing a re-vote whose edited plan differs from the recorded one");
67
+ }
68
+ if (winner.reason !== undefined && winner.reason !== plainReviewOutcome.reason) {
69
+ throw new CheckpointError("checkpoint.reopen_revote", "an env_failed reopen replays the ALREADY-RECORDED review decision — refusing a re-vote whose reviewer note differs from the recorded one");
70
+ }
71
+ }
72
+ }
73
+ let plainParkOutcome;
74
+ if (outcomeGate === "wake") {
75
+ plainParkOutcome = {
76
+ gate: "wake",
77
+ ...(wakeMessage !== undefined ? { message: wakeMessage } : {}),
78
+ };
79
+ }
80
+ else if (outcomeGate === "resource_limit") {
81
+ const decision = outcome.decision;
82
+ if (decision !== "continue") {
83
+ throw new CheckpointError("checkpoint.invalid_outcome", `resume decision "${describeSuppliedValue(decision)}" is outside the resource_limit domain — a slice resume is exactly "continue"; refusing pre-CAS, the checkpoint stays pending`);
84
+ }
85
+ plainParkOutcome = { gate: "resource_limit", decision };
86
+ }
87
+ return { plainReviewOutcome, plainParkOutcome };
88
+ }
@@ -261,7 +261,7 @@ export function createHarnessHandlers(input) {
261
261
  toolName: event.toolName,
262
262
  ...(toolLabels.get(event.toolName) !== undefined ? { label: toolLabels.get(event.toolName) } : {}),
263
263
  isError: event.isError,
264
- ...toolEndBodyFrom(event.result, event.isError, gate, prepared.abortController.signal.aborted ? gatedCallIdOf(prepared) : undefined),
264
+ ...toolEndBodyFrom(event.result, event.isError, prepared.structuredProjector, gate, prepared.abortController.signal.aborted ? gatedCallIdOf(prepared) : undefined),
265
265
  ...ident(),
266
266
  });
267
267
  announceWorkspaceMove();
@@ -56,6 +56,9 @@ export declare class Runner implements RunnerSelfSeat {
56
56
  * never a wrong destroy. */
57
57
  private readonly locallyClaimedTokens;
58
58
  private static readonly PARENT_CONSTRAINT_REGISTRY_CAP;
59
+ /** The lanes' LIVE view of `deps` ({@link RunnerDepsSeat}): a getter, never a captured object, because
60
+ * `swapModels` replaces the object and a rung reading after its own await must see the replacement. */
61
+ private readonly depsSeat;
59
62
  constructor(deps: RunnerDeps);
60
63
  /** design/73 §1 v1 — fire `RunnerDeps.onTaskOutcome` through the single swallow-guarded chokepoint
61
64
  * ({@link emitTaskOutcome}: mechanical-tier only, throwing sink never breaks the caller). Public so
@@ -227,6 +230,23 @@ export declare class Runner implements RunnerSelfSeat {
227
230
  * authority, so constraint substitution here is outside the enforced threat model (the count check
228
231
  * catches shape MISTAKES, not a untrusted trusted caller). */
229
232
  internals?: RunInternals): Promise<TaskStream>;
233
+ /**
234
+ * design/393 S3 — the resume decision ladder after admission (E3–E10), driving the eight `resume-*` lanes in
235
+ * the order the one-function ladder had: the review / park twins, the approval twin and its bindings, the
236
+ * checkpoint screen, the internals-and-config rungs (whose one window await is taken HERE, where the ladder
237
+ * took it), then the three async rungs after it — apply, preflight, claim — each entering the next in its own last
238
+ * continuation, and the post-claim hand-off to the resumed leg. Every rung throws its typed refusal pre-CAS;
239
+ * the first `return` is the leg's stream.
240
+ */
241
+ private resumeLadder;
242
+ /**
243
+ * design/393 S3 — the ladder's POST-CLAIM rung (E11), the driver's own: the post-consume hook, the answering
244
+ * face minted from the decide's answer, the resumed leg's spec (identity continuity, the existing-session
245
+ * requirement, the stripped pre-aborted preempt signal), the reopen compensation and the execution-record
246
+ * verb bound to the row, the two post-CAS abort re-checks, and the hand-off to `runTaskStream` with the plain
247
+ * twin. Entered in the claim rung's last continuation, so its first statement runs on the tick the win was read.
248
+ */
249
+ private resumeHandoff;
230
250
  /**
231
251
  * design/45 resume step: with the harness idle and the branch rewound to the suspension leaf, resolve
232
252
  * the gated tool call and close the rest of the suspended batch, all by appending `toolResult`s to the