@wenathlan/extension 1.1.61 → 1.1.63

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 (49) hide show
  1. package/README.md +5 -3
  2. package/dist/confirmgates.d.ts +60 -0
  3. package/dist/confirmgates.d.ts.map +1 -0
  4. package/dist/environments.d.ts +10 -0
  5. package/dist/environments.d.ts.map +1 -1
  6. package/dist/inboundguard.d.ts +86 -0
  7. package/dist/inboundguard.d.ts.map +1 -0
  8. package/dist/index.d.ts +8 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +1299 -3
  11. package/dist/index.js.map +4 -4
  12. package/dist/memory.d.ts +187 -1
  13. package/dist/memory.d.ts.map +1 -1
  14. package/dist/originpolicy.d.ts +10 -0
  15. package/dist/originpolicy.d.ts.map +1 -1
  16. package/dist/phishguard.d.ts +24 -0
  17. package/dist/phishguard.d.ts.map +1 -0
  18. package/dist/policy.d.ts +122 -1
  19. package/dist/policy.d.ts.map +1 -1
  20. package/dist/protocol.d.ts +88 -0
  21. package/dist/protocol.d.ts.map +1 -1
  22. package/dist/redactshots.d.ts +54 -0
  23. package/dist/redactshots.d.ts.map +1 -0
  24. package/dist/secretvault.d.ts +89 -0
  25. package/dist/secretvault.d.ts.map +1 -0
  26. package/dist/sessioninterface.d.ts +213 -0
  27. package/dist/sessioninterface.d.ts.map +1 -0
  28. package/dist/transparency.d.ts +46 -0
  29. package/dist/transparency.d.ts.map +1 -0
  30. package/dist/types.d.ts +368 -3
  31. package/dist/types.d.ts.map +1 -1
  32. package/dist/version.d.ts +1 -1
  33. package/extension/dist/background.js +1710 -55
  34. package/extension/dist/background.js.map +4 -4
  35. package/extension/dist/manifest.json +5 -1
  36. package/extension/dist/offscreen.js +4 -0
  37. package/extension/dist/offscreen.js.map +2 -2
  38. package/extension/dist/pagebridge.js.map +2 -2
  39. package/extension/dist/popup.html +1 -1
  40. package/extension/dist/popup.js +41 -0
  41. package/extension/dist/popup.js.map +2 -2
  42. package/extension/dist/sidepanel.html +1 -1
  43. package/extension/dist/sidepanel.js +462 -215
  44. package/extension/dist/sidepanel.js.map +3 -3
  45. package/extension/dist/transparencypage.html +25 -0
  46. package/extension/dist/transparencypage.js +198 -0
  47. package/extension/dist/transparencypage.js.map +7 -0
  48. package/extension/manifest.json +5 -1
  49. package/package.json +1 -1
@@ -4737,6 +4737,375 @@ var sessionmemory = class {
4737
4737
  }
4738
4738
  return kept;
4739
4739
  }
4740
+ /**
4741
+ * Security part two persistence of the 1.1.62 family.
4742
+ * The protections for secrets, messages and money live here: the secretvault metadata with labels and scopes only and never values, scoped per profile workspace; the connectallow entries with their senders shipping empty by default; the ratelimit bucket state per origin and per session; the confirm gates with their resolution events and their human action provenance; the redactshot regions per origin and page template; the phishguard verdicts with their distance scores expiring past their freshness window; the permdiff records of each installed version; the safedefaults applications with their first seen origins; and the deferred command events waiting for their bucket reset.
4743
+ * The vault values never touch this seam: only metadata persists while the values stay behind the vault seam the background wires.
4744
+ */
4745
+ /** Replaces the secretvault metadata of the profile workspaces: labels, scopes, provenance and digests only, never values. */
4746
+ async setsecretvault(entries) {
4747
+ return this.adapter.set("secretvault", entries);
4748
+ }
4749
+ /** Returns the stored secretvault metadata, oldest record first; the values live behind the vault seam and never persist. */
4750
+ async getsecretvault() {
4751
+ return await this.adapter.get("secretvault") ?? [];
4752
+ }
4753
+ /** Adds one secretvault metadata record scoped to a profile workspace; a duplicate vault id keeps its first record. */
4754
+ async addsecret(entry) {
4755
+ const entries = await this.getsecretvault();
4756
+ if (entries.some((candidate) => candidate.vaultid === entry.vaultid)) return;
4757
+ await this.setsecretvault([...entries, entry]);
4758
+ }
4759
+ /** Removes one secretvault metadata record by its vault id; the background drops the value behind the seam in the same action. */
4760
+ async removesecret(vaultid) {
4761
+ await this.setsecretvault((await this.getsecretvault()).filter((entry) => entry.vaultid !== vaultid));
4762
+ }
4763
+ /** Stamps the last use of one secretvault record: the metadata notes when the vault last released its value while the value itself stays unrecorded. */
4764
+ async stampsecretuse(vaultid, at) {
4765
+ await this.setsecretvault((await this.getsecretvault()).map((entry) => entry.vaultid === vaultid ? { ...entry, lastusedat: at } : entry));
4766
+ }
4767
+ /** Replaces the connectallow entries of external senders; the list ships empty by default with user managed entries only. */
4768
+ async setconnectallow(entries) {
4769
+ return this.adapter.set("connectallow", entries);
4770
+ }
4771
+ /** Returns the stored connectallow entries, oldest add first. */
4772
+ async getconnectallow() {
4773
+ return await this.adapter.get("connectallow") ?? [];
4774
+ }
4775
+ /** Adds one connectallow entry for an external sender; a duplicate sender id keeps its first entry. */
4776
+ async addconnectallow(entry) {
4777
+ const entries = await this.getconnectallow();
4778
+ if (entries.some((candidate) => candidate.senderid === entry.senderid)) return;
4779
+ await this.setconnectallow([...entries, entry]);
4780
+ }
4781
+ /** Removes one connectallow entry by its sender id; the origincheck drops the sender again after the removal. */
4782
+ async removeconnectallow(senderid) {
4783
+ await this.setconnectallow((await this.getconnectallow()).filter((entry) => entry.senderid !== senderid));
4784
+ }
4785
+ /** Replaces the ratelimit bucket state per origin and per session: the user configured bounds and windows with their used counts. */
4786
+ async setratelimitbuckets(buckets) {
4787
+ return this.adapter.set("ratelimitbuckets", buckets);
4788
+ }
4789
+ /** Returns the stored ratelimit buckets per origin and per session. */
4790
+ async getratelimitbuckets() {
4791
+ return await this.adapter.get("ratelimitbuckets") ?? [];
4792
+ }
4793
+ /** Upserts one ratelimit bucket: a bucket of the same origin and session replaces its state while a new pair joins the list. */
4794
+ async saveratelimitbucket(bucket) {
4795
+ const buckets = await this.getratelimitbuckets();
4796
+ await this.setratelimitbuckets(buckets.some((candidate) => candidate.origin === bucket.origin && candidate.sessionid === bucket.sessionid) ? buckets.map((candidate) => candidate.origin === bucket.origin && candidate.sessionid === bucket.sessionid ? bucket : candidate) : [...buckets, bucket]);
4797
+ }
4798
+ /** Removes the ratelimit bucket of one origin and session; the origin runs without a bucket because the bounds stay user choices only. */
4799
+ async removeratelimitbucket(origin, sessionid) {
4800
+ await this.setratelimitbuckets((await this.getratelimitbuckets()).filter((bucket) => !(bucket.origin === origin && bucket.sessionid === sessionid)));
4801
+ }
4802
+ /** Replaces the confirm gates with their payloads and states; a resolved or refused gate stays terminal for the audit trail. */
4803
+ async setgates(gates) {
4804
+ return this.adapter.set("confirmgates", gates);
4805
+ }
4806
+ /** Returns the stored confirm gates, newest open first. */
4807
+ async getgates() {
4808
+ return await this.adapter.get("confirmgates") ?? [];
4809
+ }
4810
+ /** Upserts one confirm gate: a gate of the same step keeps its latest record because one gated step carries one live gate. */
4811
+ async savegate(gate) {
4812
+ const gates = await this.getgates();
4813
+ await this.setgates(gates.some((candidate) => candidate.stepid === gate.stepid && candidate.kind === gate.kind) ? gates.map((candidate) => candidate.stepid === gate.stepid && candidate.kind === gate.kind ? gate : candidate) : [gate, ...gates]);
4814
+ }
4815
+ /** Records one gate resolution event with its human action provenance; the resolution history stays visible for the audit trail. */
4816
+ async addgateresolution(resolution) {
4817
+ await this.adapter.set("gateresolutions", [resolution, ...await this.adapter.get("gateresolutions") ?? []].slice(0, 500));
4818
+ }
4819
+ /** Returns the recorded gate resolution events with their human action provenance, newest first. */
4820
+ async getgateresolutions() {
4821
+ return await this.adapter.get("gateresolutions") ?? [];
4822
+ }
4823
+ /** Replaces the redactshot regions per origin and page template. */
4824
+ async setredactregions(regions) {
4825
+ return this.adapter.set("redactregions", regions);
4826
+ }
4827
+ /** Returns the stored redactshot regions per origin and page template, oldest rule first. */
4828
+ async getredactregions() {
4829
+ return await this.adapter.get("redactregions") ?? [];
4830
+ }
4831
+ /** Adds one redactshot region, derived from a field shape or drawn by the user. */
4832
+ async addredactregion(region) {
4833
+ await this.setredactregions([...await this.getredactregions(), region]);
4834
+ }
4835
+ /** Removes one redactshot region by its id. */
4836
+ async removeredactregion(id) {
4837
+ await this.setredactregions((await this.getredactregions()).filter((region) => region.id !== id));
4838
+ }
4839
+ /** Records one phishguard verdict with its distance score; the records stay for the audit trail while the freshness window governs the live set. */
4840
+ async addphishverdict(verdict) {
4841
+ await this.adapter.set("phishverdicts", [verdict, ...(await this.adapter.get("phishverdicts") ?? []).filter((candidate) => candidate.origin !== verdict.origin)].slice(0, 500));
4842
+ }
4843
+ /** Returns the stored phishguard verdicts with their distance scores, newest first. */
4844
+ async getphishverdicts() {
4845
+ return await this.adapter.get("phishverdicts") ?? [];
4846
+ }
4847
+ /** Expires the phishguard verdicts past the user configured freshness window: the expired verdicts keep their records for the audit trail while the guard recomputes the next login step. */
4848
+ async expirephishverdicts(freshness, now) {
4849
+ const verdicts = await this.getphishverdicts();
4850
+ if (freshness === void 0) return verdicts;
4851
+ return verdicts.filter((verdict) => now - verdict.at < freshness);
4852
+ }
4853
+ /** Records one permdiff between two installed permission versions; the record of each installed update stays for the audit trail. */
4854
+ async addpermdiff(diff) {
4855
+ await this.adapter.set("permdiffs", [diff, ...await this.adapter.get("permdiffs") ?? []].slice(0, 500));
4856
+ }
4857
+ /** Returns the recorded permdiffs of each installed update, newest first. */
4858
+ async getpermdiffs() {
4859
+ return await this.adapter.get("permdiffs") ?? [];
4860
+ }
4861
+ /** Stores the last installed permission set the permdiff of the next update compares against. */
4862
+ async setlastpermissions(permissions, version) {
4863
+ await this.adapter.set("lastpermissions", { permissions, version });
4864
+ }
4865
+ /** Returns the last installed permission set with its version; an absent record returns undefined. */
4866
+ async getlastpermissions() {
4867
+ return this.adapter.get("lastpermissions");
4868
+ }
4869
+ /** Records one safedefaults application with its first seen origin; the first visit of an unknown origin stays visible. */
4870
+ async addsafedefaultapplication(application) {
4871
+ const applications = await this.adapter.get("safedefaults") ?? [];
4872
+ if (applications.some((candidate) => candidate.origin === application.origin)) return;
4873
+ await this.adapter.set("safedefaults", [...applications, application]);
4874
+ }
4875
+ /** Returns the recorded safedefaults applications with their first seen origins, oldest first. */
4876
+ async getsafedefaultapplications() {
4877
+ return await this.adapter.get("safedefaults") ?? [];
4878
+ }
4879
+ /** Records one deferred command event with the reset time it waits for. */
4880
+ async adddeferredevent(event) {
4881
+ await this.adapter.set("deferredevents", [event, ...await this.adapter.get("deferredevents") ?? []].slice(0, 500));
4882
+ }
4883
+ /** Returns the recorded deferred command events, newest first. */
4884
+ async getdeferredevents() {
4885
+ return await this.adapter.get("deferredevents") ?? [];
4886
+ }
4887
+ /** Serves the transparency data of the transparencypage in one read: every active grant with its origin, scope and boundary, every consent window ever granted with its expiry, the connectallow entries with their senders, the permdiff records of each installed update, the safedefaults applications and the secretvault metadata with labels and scopes only. */
4888
+ async gettransparencyview() {
4889
+ return {
4890
+ allowlist: await this.getautomationallowlist(),
4891
+ profiles: await this.getoriginprofiles(),
4892
+ windows: await this.getconsentwindows(),
4893
+ connectallow: await this.getconnectallow(),
4894
+ permdiffs: await this.getpermdiffs(),
4895
+ safedefaults: await this.getsafedefaultapplications(),
4896
+ vault: await this.getsecretvault(),
4897
+ gates: await this.getgates(),
4898
+ resolutions: await this.getgateresolutions(),
4899
+ deferred: await this.getdeferredevents(),
4900
+ phishverdicts: await this.getphishverdicts()
4901
+ };
4902
+ }
4903
+ /**
4904
+ * Session interface persistence of the 1.1.63 family.
4905
+ * The five session stores live here, scoped per profile workspace: the sitenotes per origin with sensitive bodies sealed at rest, the append only scratchpad entries per task with their step provenance, the distilled runsummaries per run and origin, the correctionmemory entries per origin and kind captured from plan review, and the consentmemory entries per origin with every grant, denial, expiry and revocation carrying its boundary; beside them the semanticrecall index with fingerprint deduplication answers ranked queries inside the run scope, the incremental historysearch corpus indexes session metadata, notes and summaries as they are written, the errorsurface payloads of failed steps keep their retry hints with the policy verdict, the per tab session references isolate parallel tabs, and the export bundles notes, summaries and corrections as one audit bundle.
4906
+ * The recall seam stays documented: the local fingerprint index answers every query today while a future remote recall backend can take the same shapes behind the seam without touching the callers.
4907
+ */
4908
+ /** Replaces the stored site notes; a sensitive note carries its sealedbody only so the plain body never persists. */
4909
+ async setsitenotes(notes) {
4910
+ return this.adapter.set("sitenotes", notes);
4911
+ }
4912
+ /** Returns the stored site notes, oldest update first. */
4913
+ async getsitenotes() {
4914
+ return await this.adapter.get("sitenotes") ?? [];
4915
+ }
4916
+ /** Reads the site notes of one origin only; the read gate keeps the origin inside the session grants. */
4917
+ async readsitenotes(origin) {
4918
+ return (await this.getsitenotes()).filter((note) => note.origin === origin);
4919
+ }
4920
+ /** Writes one site note: a note of the same id keeps its latest edit while a new note joins the store. */
4921
+ async writesitenote(note) {
4922
+ const notes = await this.getsitenotes();
4923
+ await this.setsitenotes(notes.some((candidate) => candidate.id === note.id) ? notes.map((candidate) => candidate.id === note.id ? note : candidate) : [...notes, note]);
4924
+ }
4925
+ /** Removes one site note by its id. */
4926
+ async removesitenote(id) {
4927
+ await this.setsitenotes((await this.getsitenotes()).filter((note) => note.id !== id));
4928
+ }
4929
+ /** Expires the site notes past the user configured window; an absent window keeps every note. */
4930
+ async expiresitenotes(retention, now) {
4931
+ if (retention === void 0) return await this.getsitenotes();
4932
+ const kept = (await this.getsitenotes()).filter((note) => now - note.updatedat < retention);
4933
+ await this.setsitenotes(kept);
4934
+ return kept;
4935
+ }
4936
+ /** Replaces the stored scratchpad entries per task. */
4937
+ async setscratchpad(entries) {
4938
+ return this.adapter.set("scratchpad", entries);
4939
+ }
4940
+ /** Returns every stored scratchpad entry, newest first. */
4941
+ async getscratchpadall() {
4942
+ return await this.adapter.get("scratchpad") ?? [];
4943
+ }
4944
+ /** Appends one scratchpad entry: the pad stays append only so no later write rewrites an earlier entry. */
4945
+ async appendscratchentry(entry) {
4946
+ await this.setscratchpad([entry, ...await this.getscratchpadall()]);
4947
+ }
4948
+ /** Reads the scratchpad of one task session, newest first; entries of another task never cross the boundary. */
4949
+ async readscratchpad(taskid, sessionid) {
4950
+ return (await this.getscratchpadall()).filter((entry) => entry.taskid === taskid && entry.sessionid === sessionid);
4951
+ }
4952
+ /** Prunes the scratchpad entries past the user configured window; an absent window keeps every entry. */
4953
+ async prunescratchentries(window2, now) {
4954
+ if (window2 === void 0) return await this.getscratchpadall();
4955
+ const kept = (await this.getscratchpadall()).filter((entry) => now - entry.at < window2);
4956
+ await this.setscratchpad(kept);
4957
+ return kept;
4958
+ }
4959
+ /** Stores one distilled run summary of a completed run. */
4960
+ async setrunsummary(summary) {
4961
+ return this.adapter.set(`runsummary:${summary.runid}`, summary);
4962
+ }
4963
+ /** Returns the stored run summary of one run; an absent summary returns undefined. */
4964
+ async getrunsummary(runid) {
4965
+ return this.adapter.get(`runsummary:${runid}`);
4966
+ }
4967
+ /** Lists the stored run summaries, oldest distillation first, optionally filtered by origin. */
4968
+ async listrunsummaries(origin) {
4969
+ const index = await this.adapter.get("runsummaryindex") ?? [];
4970
+ const summaries = [];
4971
+ for (const runid of index) {
4972
+ const summary = await this.getrunsummary(runid);
4973
+ if (summary) summaries.push(summary);
4974
+ }
4975
+ const filtered = origin === void 0 ? summaries : summaries.filter((summary) => summary.origins.includes(origin));
4976
+ return filtered.sort((one, two) => one.distilledat - two.distilledat);
4977
+ }
4978
+ /** Tracks one run in the run summary index so the listing reads every stored summary. */
4979
+ async trackrunsummary(runid) {
4980
+ const index = await this.adapter.get("runsummaryindex") ?? [];
4981
+ if (!index.includes(runid)) await this.adapter.set("runsummaryindex", [...index, runid]);
4982
+ }
4983
+ /** Expires the run summaries past the user configured window; an absent window keeps every summary. */
4984
+ async expirerunsummaries(retention, now) {
4985
+ const summaries = await this.listrunsummaries();
4986
+ if (retention === void 0) return summaries;
4987
+ const kept = [];
4988
+ for (const summary of summaries) {
4989
+ if (now - summary.distilledat > retention) await this.adapter.set(`runsummary:${summary.runid}`, { ...summary, steps: [], kinds: [], origins: summary.origins });
4990
+ else kept.push(summary);
4991
+ }
4992
+ return kept;
4993
+ }
4994
+ /** Replaces the semantic recall index with its fingerprint deduplicated entries. */
4995
+ async setrecallindex(index) {
4996
+ return this.adapter.set("recallindex", index);
4997
+ }
4998
+ /** Returns the stored semantic recall index entries, newest first. */
4999
+ async getrecallindex() {
5000
+ return await this.adapter.get("recallindex") ?? [];
5001
+ }
5002
+ /** Adds one recall index entry with fingerprint deduplication: a repeated extraction keeps its first entry. */
5003
+ async addrecallentry(entry) {
5004
+ const index = await this.getrecallindex();
5005
+ if (index.some((candidate) => candidate.fingerprint === entry.fingerprint && candidate.origin === entry.origin)) return;
5006
+ await this.setrecallindex([entry, ...index]);
5007
+ }
5008
+ /** Answers one semantic recall query across the extraction stores: the local index ranks by text similarity inside the run scope and returns the provenance of every match. */
5009
+ async semanticrecall(query, scope, rank) {
5010
+ return rank(await this.getrecallindex(), query, scope);
5011
+ }
5012
+ /** Expires the recall index entries past the user configured window; the extraction records themselves stay for the audit trail. */
5013
+ async expirerecallentries(window2, now) {
5014
+ if (window2 === void 0) return await this.getrecallindex();
5015
+ const kept = (await this.getrecallindex()).filter((entry) => now - entry.at < window2);
5016
+ await this.setrecallindex(kept);
5017
+ return kept;
5018
+ }
5019
+ /** Replaces the stored correction memory entries per origin and kind. */
5020
+ async setcorrections(corrections) {
5021
+ return this.adapter.set("corrections", corrections);
5022
+ }
5023
+ /** Returns the stored correction memory entries, newest first, optionally filtered by origin and kind. */
5024
+ async getcorrections(filter) {
5025
+ const entries = await this.adapter.get("corrections") ?? [];
5026
+ return entries.filter((entry) => (filter?.origin === void 0 || entry.origin === filter.origin) && (filter?.kind === void 0 || entry.kind === filter.kind));
5027
+ }
5028
+ /** Records one correction memory entry captured from a plan review edit or rejection. */
5029
+ async addcorrection(entry) {
5030
+ await this.setcorrections([entry, ...await this.adapter.get("corrections") ?? []]);
5031
+ }
5032
+ /** Expires the correction memory entries past the user configured window; an absent window keeps every correction. */
5033
+ async expirecorrectionentries(window2, now) {
5034
+ if (window2 === void 0) return await this.getcorrections();
5035
+ const kept = (await this.getcorrections()).filter((entry) => now - entry.at < window2);
5036
+ await this.setcorrections(kept);
5037
+ return kept;
5038
+ }
5039
+ /** Replaces the stored consent memory entries per origin. */
5040
+ async setconsentmemory(entries) {
5041
+ return this.adapter.set("consentmemory", entries);
5042
+ }
5043
+ /** Returns the stored consent memory entries, newest first, optionally filtered by origin. */
5044
+ async getconsentmemory(origin) {
5045
+ const entries = await this.adapter.get("consentmemory") ?? [];
5046
+ return origin === void 0 ? entries : entries.filter((entry) => entry.origin === origin);
5047
+ }
5048
+ /** Records one consent memory entry per origin: every grant, denial, expiry and revocation lands with its boundary and kinds. */
5049
+ async addconsentmemoryentry(entry) {
5050
+ await this.setconsentmemory([entry, ...await this.adapter.get("consentmemory") ?? []]);
5051
+ }
5052
+ /** Replaces the stored error surface payloads of failed steps. */
5053
+ async seterrorsurfaces(surfaces) {
5054
+ return this.adapter.set("errorsurfaces", surfaces);
5055
+ }
5056
+ /** Returns the stored error surface payloads, newest first, optionally filtered by step. */
5057
+ async geterrorsurfaces(stepid) {
5058
+ const surfaces = await this.adapter.get("errorsurfaces") ?? [];
5059
+ return stepid === void 0 ? surfaces : surfaces.filter((surface) => surface.stepid === stepid);
5060
+ }
5061
+ /** Records one error surface payload of a failed step with its retry hint and the policy verdict. */
5062
+ async adderrorsurface(surface) {
5063
+ await this.seterrorsurfaces([surface, ...await this.adapter.get("errorsurfaces") ?? []].slice(0, 500));
5064
+ }
5065
+ /** Replaces the incremental history search corpus of session metadata, notes and run summaries. */
5066
+ async sethistoryindex(corpus) {
5067
+ return this.adapter.set("historyindex", corpus);
5068
+ }
5069
+ /** Returns the incremental history search corpus, newest entry first. */
5070
+ async gethistoryindex() {
5071
+ return await this.adapter.get("historyindex") ?? [];
5072
+ }
5073
+ /** Adds one corpus entry to the incremental history index on each store write. */
5074
+ async addhistoryentry(entry) {
5075
+ const corpus = await this.gethistoryindex();
5076
+ await this.sethistoryindex([entry, ...corpus.filter((candidate) => !(candidate.source === entry.source && candidate.id === entry.id))]);
5077
+ }
5078
+ /** Answers one history search query against the incremental corpus with the matched terms highlighted. */
5079
+ async historysearch(query, search) {
5080
+ return search(await this.gethistoryindex(), query);
5081
+ }
5082
+ /** Stores one per tab session reference so parallel tabs never collide inside the session stores. */
5083
+ async settabsession(ref) {
5084
+ return this.adapter.set(`tabsession:${ref.tabid}`, ref);
5085
+ }
5086
+ /** Returns the per tab session reference of one tab; an absent reference returns undefined. */
5087
+ async gettabsession(tabid2) {
5088
+ return this.adapter.get(`tabsession:${tabid2}`);
5089
+ }
5090
+ /** Lists every per tab session reference so the sessiongrid reads the per tab lock state of concurrent sessions. */
5091
+ async listtabsessions() {
5092
+ const tabs = await this.adapter.get("tabsessionindex") ?? [];
5093
+ const refs = [];
5094
+ for (const tabid2 of tabs) {
5095
+ const ref = await this.gettabsession(tabid2);
5096
+ if (ref) refs.push(ref);
5097
+ }
5098
+ return refs;
5099
+ }
5100
+ /** Tracks one tab in the per tab session index so the listing reads every isolated reference. */
5101
+ async tracktabsession(tabid2) {
5102
+ const tabs = await this.adapter.get("tabsessionindex") ?? [];
5103
+ if (!tabs.includes(tabid2)) await this.adapter.set("tabsessionindex", [...tabs, tabid2]);
5104
+ }
5105
+ /** Exports the site notes, the run summaries and the correction memory as one audit bundle: sensitive note bodies stay sealed in the export. */
5106
+ async exportsessionbundle(exportedat) {
5107
+ return { kind: "sessionbundle", notes: await this.getsitenotes(), summaries: await this.listrunsummaries(), corrections: await this.getcorrections(), exportedat };
5108
+ }
4740
5109
  };
4741
5110
  function mediakindof(record2) {
4742
5111
  if ("pages" in record2) return "pdf";
@@ -5018,6 +5387,11 @@ function isolatedinjection(step) {
5018
5387
  }
5019
5388
  return { world: "ISOLATED", code: step.value, args };
5020
5389
  }
5390
+ var runsummarytask = "runsummary";
5391
+ function summaryrequestof(input) {
5392
+ if (input.payload.trim() === "") throw new Error("The runsummary request needs its payload reference.");
5393
+ return { id: input.id, runid: input.runid, stepid: input.sessionid, task: runsummarytask, payload: input.payload, transferables: [], sentat: input.sentat };
5394
+ }
5021
5395
 
5022
5396
  // toolcatalog.ts
5023
5397
  var toolcatalogversion = 1;
@@ -6673,6 +7047,226 @@ function consolediff(input) {
6673
7047
  return { base: input.baseid, target: input.targetid, lines, added: added.length, removed: removed.length, repeated: repeated.length, at: input.now };
6674
7048
  }
6675
7049
 
7050
+ // inboundguard.ts
7051
+ function shapeof(value) {
7052
+ if (typeof value === "string") return "string";
7053
+ if (typeof value === "number") return "number";
7054
+ if (typeof value === "boolean") return "boolean";
7055
+ if (Array.isArray(value)) return "array";
7056
+ return "object";
7057
+ }
7058
+ function schemacheck(input) {
7059
+ const errors = [];
7060
+ for (const [field, value] of Object.entries(input.command)) {
7061
+ const expected = input.schema[field];
7062
+ if (expected === void 0) {
7063
+ errors.push({ path: field, expected: "absent", found: shapeof(value), reason: `The ${field} field sits absent from the declared grammar of the command; schemastrict refuses unknown fields before dispatch.` });
7064
+ continue;
7065
+ }
7066
+ if (expected === "absent") {
7067
+ errors.push({ path: field, expected: "absent", found: shapeof(value), reason: `The ${field} field carries no value under the declared grammar; schemastrict refuses it before dispatch.` });
7068
+ continue;
7069
+ }
7070
+ if (shapeof(value) !== expected) errors.push({ path: field, expected, found: shapeof(value), reason: `The ${field} field expects a ${expected} while the command carries a ${shapeof(value)}; schemastrict refuses the shape mismatch before dispatch.` });
7071
+ }
7072
+ for (const field of input.required ?? []) {
7073
+ if (input.command[field] === void 0) errors.push({ path: field, expected: input.schema[field] ?? "string", found: "absent", reason: `The ${field} field is required by the declared grammar and the command carries no value; schemastrict refuses the incomplete command before dispatch.` });
7074
+ }
7075
+ return { valid: errors.length === 0, errors };
7076
+ }
7077
+ function origincheckof(input) {
7078
+ const sender = input.senderid ?? "an unknown sender";
7079
+ const origin = input.senderorigin ?? "";
7080
+ if (input.senderid === input.extensionid) return { accepted: true, sender, origin, reason: "The sender is this extension itself; the internal surface accepts." };
7081
+ if (input.senderid !== void 0 && input.connectallow.some((entry) => entry.senderid === input.senderid && (entry.origin === void 0 || entry.origin === origin))) {
7082
+ return { accepted: true, sender, origin, reason: `The sender ${sender} sits in the connectallow list the user manages${origin !== "" ? ` for ${origin}` : ""}; the message accepts.` };
7083
+ }
7084
+ if (input.senderid === void 0) return { accepted: false, sender, origin, reason: "The message carries no sender identity; the guard drops it before any handler runs." };
7085
+ return { accepted: false, sender, origin, reason: `The sender ${sender} sits absent from the connectallow list; the guard drops the message without handler execution.` };
7086
+ }
7087
+ function portaccept(input) {
7088
+ const verdict = origincheckof(input);
7089
+ if (!verdict.accepted) return { ...verdict, reason: `The port ${input.portname} closes at its handshake: ${verdict.reason}` };
7090
+ return { ...verdict, reason: `The port ${input.portname} accepted its handshake: ${verdict.reason}` };
7091
+ }
7092
+ function connectallowentryof(input) {
7093
+ if (input.senderid.trim() === "") throw new Error("The connectallow entry needs its sender id.");
7094
+ if (input.displayname.trim() === "") throw new Error("The connectallow entry needs its display name.");
7095
+ return { senderid: input.senderid.trim(), displayname: input.displayname.trim(), ...input.origin !== void 0 && input.origin.trim() !== "" ? { origin: input.origin.trim() } : {}, addedat: input.now };
7096
+ }
7097
+ function bucketboundsvalid(limit, window2) {
7098
+ if (!Number.isFinite(limit) || limit <= 0) return { valid: false, reason: "The ratelimit bucket limit stays a positive user value; no hidden ceiling exists." };
7099
+ if (!Number.isFinite(window2) || window2 <= 0) return { valid: false, reason: "The ratelimit bucket window stays a positive user value in milliseconds; the window reset stays the user's choice." };
7100
+ return { valid: true, reason: `The bucket bound of ${limit} commands per ${window2} milliseconds stays the user configured choice with no hidden ceiling.` };
7101
+ }
7102
+ function bucketof(input) {
7103
+ const bounds = bucketboundsvalid(input.limit, input.window);
7104
+ if (!bounds.valid) throw new Error(bounds.reason);
7105
+ return { origin: input.origin, sessionid: input.sessionid, limit: input.limit, window: input.window, used: 0, windowstartedat: input.now, resetsat: input.now + input.window };
7106
+ }
7107
+ function bucketconsume(input) {
7108
+ if (input.now >= input.bucket.resetsat) {
7109
+ const fresh = { ...input.bucket, used: 0, windowstartedat: input.now, resetsat: input.now + input.bucket.window };
7110
+ return { allowed: true, deferred: false, bucket: { ...fresh, used: 1 }, resetsat: fresh.resetsat, reason: `The bucket window of ${input.bucket.origin} reset and the command consumes the first slot of ${fresh.limit}.` };
7111
+ }
7112
+ if (input.bucket.used < input.bucket.limit) {
7113
+ return { allowed: true, deferred: false, bucket: { ...input.bucket, used: input.bucket.used + 1 }, resetsat: input.bucket.resetsat, reason: `The command consumes slot ${input.bucket.used + 1} of ${input.bucket.limit} in the bucket of ${input.bucket.origin}.` };
7114
+ }
7115
+ return { allowed: false, deferred: true, bucket: input.bucket, resetsat: input.bucket.resetsat, reason: `The bucket of ${input.bucket.origin} holds its ${input.bucket.limit} command bound; the command defers until the window resets at ${input.bucket.resetsat}.` };
7116
+ }
7117
+ function deferredeventof(input) {
7118
+ if (input.stepid.trim() === "" || input.kind.trim() === "") throw new Error("The deferred event needs its step and kind.");
7119
+ return { id: input.id ?? randomid(), stepid: input.stepid, kind: input.kind, origin: input.origin, reason: input.reason, resetsat: input.resetsat, at: input.now };
7120
+ }
7121
+
7122
+ // confirmgates.ts
7123
+ function stepoptions2(step) {
7124
+ if (!step.options) return {};
7125
+ try {
7126
+ const parsed = JSON.parse(step.options);
7127
+ return Boolean(parsed) && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
7128
+ } catch {
7129
+ return {};
7130
+ }
7131
+ }
7132
+ function gatekindfor(classes) {
7133
+ if (classes.includes("payment")) return "confirmpay";
7134
+ if (classes.includes("delete")) return "confirmdelete";
7135
+ if (classes.includes("credential")) return "confirmcreds";
7136
+ return void 0;
7137
+ }
7138
+ function paypayload(input) {
7139
+ const payload = { payeeorigin: input.payeeorigin };
7140
+ if (input.amount !== void 0 && input.amount.trim() !== "") payload.amount = input.amount.trim();
7141
+ if (input.target !== void 0 && input.target.trim() !== "") payload.target = input.target.trim();
7142
+ return payload;
7143
+ }
7144
+ function deletepayload(input) {
7145
+ const payload = { scope: input.scope, irreversibility: input.irreversibility };
7146
+ if (input.target !== void 0 && input.target.trim() !== "") payload.target = input.target.trim();
7147
+ return payload;
7148
+ }
7149
+ function credspayload(label) {
7150
+ if (label.trim() === "") throw new Error("The confirmcreds gate names its credential label; the value never appears.");
7151
+ return { label: label.trim() };
7152
+ }
7153
+ function opengate(input) {
7154
+ if (input.stepid.trim() === "" || input.runid.trim() === "" || input.origin.trim() === "") throw new Error("The confirm gate needs its step, run and origin.");
7155
+ if (Object.keys(input.payload).length === 0) throw new Error("The confirm gate carries the payload the human reviews.");
7156
+ return { gateid: input.gateid ?? randomid(), kind: input.kind, stepid: input.stepid, runid: input.runid, origin: input.origin, payload: { ...input.payload }, state: "open", openedat: input.now };
7157
+ }
7158
+ function gatestateof(gates, stepid) {
7159
+ const gate = [...gates].reverse().find((candidate) => candidate.stepid === stepid);
7160
+ if (gate === void 0) return { state: "none" };
7161
+ return { state: gate.state, gate };
7162
+ }
7163
+ function resolvegate(input) {
7164
+ if (input.actor.trim() === "") throw new Error("The gate resolution names its acting user; only a human resolves a gate.");
7165
+ const gate = input.gates.find((candidate) => candidate.gateid === input.gateid);
7166
+ if (gate === void 0) return { gates: input.gates };
7167
+ if (gate.state !== "open") return { gates: input.gates };
7168
+ const resolution = { gateid: gate.gateid, kind: gate.kind, stepid: gate.stepid, decision: input.decision, actor: input.actor, at: input.now };
7169
+ return { gates: input.gates.map((candidate) => candidate.gateid === input.gateid ? { ...candidate, state: input.decision, resolvedat: input.now, actor: input.actor } : candidate), resolution };
7170
+ }
7171
+ function gateprompttext(gate) {
7172
+ if (gate.kind === "confirmpay") {
7173
+ const amount = gate.payload.amount !== void 0 ? `the amount ${gate.payload.amount}` : "an amount the step options name";
7174
+ const target = gate.payload.target !== void 0 ? ` on ${gate.payload.target}` : "";
7175
+ return `Approve the payment of ${amount} to ${gate.payload.payeeorigin}${target}? The step dispatches only after this distinct human action.`;
7176
+ }
7177
+ if (gate.kind === "confirmdelete") {
7178
+ const target = gate.payload.target !== void 0 ? ` on ${gate.payload.target}` : "";
7179
+ return `Approve the destructive delete${target} scoped to ${gate.payload.scope}? ${gate.payload.irreversibility} The step dispatches only after this distinct human action.`;
7180
+ }
7181
+ return `Approve the use of the credential ${gate.payload.label} on ${gate.origin}? The value stays behind the vault; the label is everything this prompt shows.`;
7182
+ }
7183
+ function gateforstep(input) {
7184
+ const kind = gatekindfor(input.classes);
7185
+ if (kind === void 0) return void 0;
7186
+ const options = stepoptions2(input.step);
7187
+ if (kind === "confirmpay") {
7188
+ const amount = typeof options.amount === "string" ? options.amount : typeof options.value === "string" ? options.value : void 0;
7189
+ return opengate({ kind, stepid: input.step.id, runid: input.runid, origin: input.origin, payload: paypayload({ ...amount !== void 0 && amount !== "" ? { amount } : {}, payeeorigin: String(options.payeeorigin ?? input.origin), ...input.step.target !== void 0 && input.step.target !== "" ? { target: input.step.target } : {} }), now: input.now });
7190
+ }
7191
+ if (kind === "confirmdelete") {
7192
+ return opengate({ kind, stepid: input.step.id, runid: input.runid, origin: input.origin, payload: deletepayload({ ...input.step.target !== void 0 && input.step.target !== "" ? { target: input.step.target } : {}, scope: String(options.scope ?? input.origin), irreversibility: String(options.irreversibility ?? "A destructive delete destroys state the page cannot restore.") }), now: input.now });
7193
+ }
7194
+ if (input.credentiallabel === void 0 || input.credentiallabel.trim() === "") return void 0;
7195
+ return opengate({ kind, stepid: input.step.id, runid: input.runid, origin: input.origin, payload: credspayload(input.credentiallabel), now: input.now });
7196
+ }
7197
+
7198
+ // phishguard.ts
7199
+ function stepoptions3(step) {
7200
+ if (!step.options) return {};
7201
+ try {
7202
+ const parsed = JSON.parse(step.options);
7203
+ return Boolean(parsed) && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
7204
+ } catch {
7205
+ return {};
7206
+ }
7207
+ }
7208
+ function credentialstep(step) {
7209
+ const credentialkinds2 = /* @__PURE__ */ new Set(["consentpassword", "saveapikey", "handleauth", "authflow", "fillcard", "fillcode"]);
7210
+ if (credentialkinds2.has(step.kind)) return true;
7211
+ const options = stepoptions3(step);
7212
+ const fields = Array.isArray(options.fields) ? options.fields.filter((item) => Boolean(item) && typeof item === "object") : [];
7213
+ const names = [...fields.map((field) => typeof field.name === "string" ? field.name : ""), typeof options.field === "string" ? options.field : "", step.target ?? ""].map((name) => name.toLowerCase());
7214
+ return names.some((name) => name.includes("password") || name.includes("passwd") || name.includes("passphrase") || name.includes("token") || name.includes("secret") || name.includes("apikey"));
7215
+ }
7216
+ function originlabels(origin) {
7217
+ const host = origin.trim().replace(/^[a-z][a-z0-9+.-]*:\/\//i, "").split("/")[0] ?? "";
7218
+ return host.split(".").filter((label) => label !== "").reverse();
7219
+ }
7220
+ function labeldistance(one, two) {
7221
+ const rows = one.length + 1;
7222
+ const columns = two.length + 1;
7223
+ let previous = Array.from({ length: columns }, (_, index) => index);
7224
+ for (let row = 1; row < rows; row += 1) {
7225
+ const current = [row, ...Array.from({ length: columns - 1 }, () => 0)];
7226
+ for (let column = 1; column < columns; column += 1) {
7227
+ const substitution = (previous[column - 1] ?? 0) + (one[row - 1] === two[column - 1] ? 0 : 1);
7228
+ current[column] = Math.min((previous[column] ?? 0) + 1, (current[column - 1] ?? 0) + 1, substitution);
7229
+ }
7230
+ previous = current;
7231
+ }
7232
+ return previous[columns - 1] ?? Math.max(one.length, two.length);
7233
+ }
7234
+ function lookalikedistance(one, two) {
7235
+ if (one.trim() === "" || two.trim() === "") return 1;
7236
+ if (one === two) return 0;
7237
+ const first = originlabels(one);
7238
+ const second = originlabels(two);
7239
+ const edits = labeldistance(first, second);
7240
+ const longest = Math.max(first.length, second.length);
7241
+ if (longest === 0) return 1;
7242
+ const distance = edits / longest;
7243
+ return Math.min(1, Math.max(0, distance));
7244
+ }
7245
+ function phishthresholdvalid(threshold) {
7246
+ if (!Number.isFinite(threshold) || threshold <= 0 || threshold >= 1) return { valid: false, reason: "The phishguard threshold stays a user choice between zero and one; the lookalike line never defaults." };
7247
+ return { valid: true, reason: `The lookalike threshold ${threshold} stays the user configured line a login origin crosses at its own risk.` };
7248
+ }
7249
+ function phishverdictof(input) {
7250
+ const threshold = phishthresholdvalid(input.threshold);
7251
+ if (!threshold.valid) throw new Error(threshold.reason);
7252
+ if (input.granted.includes(input.origin)) {
7253
+ return { origin: input.origin, distance: 0, threshold: input.threshold, blocked: false, reason: `The login origin ${input.origin} sits among the granted origins; no lookalike watch applies.`, at: input.now };
7254
+ }
7255
+ let matchedorigin;
7256
+ let distance = 1;
7257
+ for (const granted of input.granted) {
7258
+ const candidate = lookalikedistance(input.origin, granted);
7259
+ if (candidate < distance) {
7260
+ distance = candidate;
7261
+ matchedorigin = granted;
7262
+ }
7263
+ }
7264
+ if (matchedorigin !== void 0 && distance <= input.threshold) {
7265
+ return { origin: input.origin, matchedorigin, distance, threshold: input.threshold, blocked: true, reason: `The login origin ${input.origin} sits ${distance} away from the granted origin ${matchedorigin} and crosses the user threshold ${input.threshold}; the credential step blocks and the deny event names ${matchedorigin}.`, at: input.now };
7266
+ }
7267
+ return { origin: input.origin, ...matchedorigin !== void 0 ? { matchedorigin } : {}, distance, threshold: input.threshold, blocked: false, reason: matchedorigin !== void 0 ? `The login origin ${input.origin} sits ${distance} away from its closest granted origin ${matchedorigin} and stays under the user threshold ${input.threshold}.` : `The login origin ${input.origin} carries no granted origin to resemble; the watch records the first visit.`, at: input.now };
7268
+ }
7269
+
6676
7270
  // policy.ts
6677
7271
  var sensitiveactions = /* @__PURE__ */ new Set(["click", "type", "navigate", "select", "presskey", "drag", "drop", "upload", "clear", "check", "uncheck", "toggle", "submit", "reload", "back", "forward", "writestorage", "setattribute", "removeattribute", "evaluate", "tabcreate", "tabactivate", "tabclose", "tabreload", "windowcreate", "windowclose", "windowresize", "downloadfile", "clickpoint", "shiftclick", "dismissdialog", "enterframe", "typetime", "appendtext", "setvalue", "typeedit", "keyhold", "keyrelease", "submitsearch", "selectmulti", "chooseradio", "setslider", "setdate", "setcolor", "openlink", "openprivate", "reloadcache", "stopnav", "followlink", "spanav", "rewritequery", "setfragment", "navlist", "navprofile", "handleauth", "printpdf", "prefetch", "preconnect", "deeplink", "reopentab", "pausenav", "navrate", "openclipboard", "batchopen", "duplicatetab", "closepattern", "pintab", "mutetab", "movetab", "movetabwindow", "grouptabs", "colorgroup", "collapsegroup", "discardtab", "reloadtabs", "zoomin", "zoomout", "switchtab", "maximizewindow", "minimizewindow", "restorewindow", "focuswindow", "scratchwindow", "incognitowindow", "restoretab", "restorelayout", "reopenrun", "badgetab", "fillform", "filllabel", "fillplaceholder", "submitform", "retryform", "runwizard", "selectchain", "picktypeahead", "pickdate", "attachfile", "fillcard", "fillcode", "consentpassword", "exportcsv", "exportjson", "exportexcel", "copytable", "pushsheets", "streamdisk", "paginateextract", "resumeextract", "batchdownload", "pausedownload", "resumedownload", "interceptmime", "readclipboard", "writeclipboard", "copyscreen", "quarantinedownload", "scanvirus", "cleanupartifacts", "recordscreen", "captureaudio", "downloadimages", "callrest", "callgraphql", "sendmessage", "blockrequest", "mockresponse", "rewriteheaders", "setcookies", "clearcookies", "authflow", "saveapikey", "routeproxy", "postform", "postfiles", "attachcdp", "detachcdp", "cdpcmd", "overridescript", "heapshot", "profilecpu", "capturesourcemaps", "emulatedevice", "emulatenetwork", "emulatelocate", "setuseragent", "overridepermission", "restoresession", "exportsessions", "importsessions", "runworkflow", "visitrule", "urlrule", "menurule", "keyrule", "buttonrule", "cronrule", "intervalrule", "urllistrule", "webhookrule", "eventrule"]);
6678
7272
  var interactionactions = /* @__PURE__ */ new Set(["focus", "scroll", "hover", "clickdeep", "rightclick", "doubleclick", "scrollpage", "scrollby", "scrollend", "scrolltop", "fullscreen", "zoomset", "movepointer", "clicktext", "clickaria", "clickname", "expanddetails", "pierceshadow", "retryaction", "capturebodies", "setbreakpoint", "stepcode", "watchexpr", "loop", "repeatuntil", "whileloop", "foreach", "parallel", "trycatch"]);
@@ -9923,6 +10517,106 @@ function logreadgate(input) {
9923
10517
  if (!input.valid) return { allowed: false, reason: input.brokenat !== void 0 ? `The log chain breaks at entry ${input.brokenat}; the audit accessor refuses the read of a forged record.` : "The log chain fails its verification; the audit accessor refuses the read of a forged record." };
9924
10518
  return { allowed: true, reason: "The log chain verifies from the genesis hash to the last entry; the audit accessor serves the entries." };
9925
10519
  }
10520
+ function schemaguardgate(input) {
10521
+ if (input.errors.length === 0) return { allowed: true, reason: "The inbound command matches its declared schemastrict grammar field by field." };
10522
+ const first = input.errors[0];
10523
+ return { allowed: false, reason: `${input.errors.length} schema error${input.errors.length === 1 ? "" : "s"} refuse the command before dispatch: ${input.errors.map((error) => error.reason).join(" ")}${first !== void 0 ? ` The first error sits at ${first.path} expecting ${first.expected}.` : ""}` };
10524
+ }
10525
+ function origincheckgate(input) {
10526
+ if (!input.verdict.accepted) return { allowed: false, reason: input.verdict.reason };
10527
+ return { allowed: true, reason: input.verdict.reason };
10528
+ }
10529
+ function ratelimitboundsvalid(limit, window2) {
10530
+ const bounds = bucketboundsvalid(limit, window2);
10531
+ if (!bounds.valid) return { allowed: false, reason: bounds.reason };
10532
+ return { allowed: true, reason: bounds.reason };
10533
+ }
10534
+ function confirmpaygate(input) {
10535
+ const kind = gatekindfor(input.classes);
10536
+ if (kind !== "confirmpay") return { allowed: true, reason: "The step carries no payment class and needs no confirmpay gate." };
10537
+ if (input.state === "resolved") return { allowed: true, reason: "The human resolved the confirmpay gate of the payment step; the step dispatches with its reviewed amount, payee origin and target." };
10538
+ if (input.state === "refused") return { allowed: false, reason: "The human refused the confirmpay gate of the payment step; the payment never dispatches." };
10539
+ if (input.state === "open") return { allowed: false, reason: "The confirmpay gate of the payment step stays open with the amount, the payee origin and the target element; the executor pauses until the human resolves it and no timeout ever resolves a gate." };
10540
+ return { allowed: false, reason: "The payment step opens its confirmpay gate with the amount, the payee origin and the target element; the executor pauses until one distinct human action resolves it." };
10541
+ }
10542
+ function confirmdeletegate(input) {
10543
+ const kind = gatekindfor(input.classes);
10544
+ if (kind !== "confirmdelete") return { allowed: true, reason: "The step carries no delete class and needs no confirmdelete gate." };
10545
+ if (input.state === "resolved") return { allowed: true, reason: "The human resolved the confirmdelete gate of the destructive step; the step dispatches with its reviewed target, scope and irreversibility." };
10546
+ if (input.state === "refused") return { allowed: false, reason: "The human refused the confirmdelete gate of the destructive step; the deletion never dispatches." };
10547
+ if (input.state === "open") return { allowed: false, reason: "The confirmdelete gate of the destructive step stays open with the target, the scope and the irreversibility; the executor pauses until the human resolves it and no timeout ever resolves a gate." };
10548
+ return { allowed: false, reason: "The destructive step opens its confirmdelete gate with the target, the scope and the irreversibility; the executor pauses until one distinct human action resolves it." };
10549
+ }
10550
+ function confirmcredsgate(input) {
10551
+ const kind = gatekindfor(input.classes);
10552
+ if (kind !== "confirmcreds") return { allowed: true, reason: "The step carries no credential class and needs no confirmcreds gate." };
10553
+ if (input.state === "resolved") return { allowed: true, reason: "The human resolved the confirmcreds gate of the credential step; the step reads its value from the vault at the last possible moment and no log records it." };
10554
+ if (input.state === "refused") return { allowed: false, reason: "The human refused the confirmcreds gate of the credential step; the credential never dispatches." };
10555
+ if (input.state === "open") return { allowed: false, reason: "The confirmcreds gate of the credential step stays open with its credential label only; the executor pauses until the human resolves it and no timeout ever resolves a gate." };
10556
+ return { allowed: false, reason: "The credential step opens its confirmcreds gate with its credential label only; the executor pauses until one distinct human action resolves it." };
10557
+ }
10558
+ function phishthresholdgate(threshold) {
10559
+ const verdict = phishthresholdvalid(threshold);
10560
+ if (!verdict.valid) return { allowed: false, reason: verdict.reason };
10561
+ return { allowed: true, reason: verdict.reason };
10562
+ }
10563
+ function phishguardgate(input) {
10564
+ if (input.verdict.blocked) return { allowed: false, reason: input.verdict.reason };
10565
+ return { allowed: true, reason: input.verdict.reason };
10566
+ }
10567
+ function safedefaultsgate(input) {
10568
+ if (input.profile !== void 0) return { allowed: true, reason: `The origin profile of ${input.profile.origin} exists; the safedefaults posture stays out of the decision.` };
10569
+ if (!input.sensitive) return { allowed: true, reason: "The non-sensitive step rides the reads only baseline of the safedefaults posture; the first visit grants reads alone." };
10570
+ return { allowed: false, reason: `No origin profile exists and the safedefaults posture denies the sensitive ${input.classes.length > 0 ? input.classes.join(" and ") : "by default"} step; open the originprofile editor to widen the profile the user controls.` };
10571
+ }
10572
+ function vaultsecretgate(input) {
10573
+ if (input.leaks.length > 0) return { allowed: false, reason: `The plan carries ${input.leaks.length} plaintext secret value${input.leaks.length === 1 ? "" : "s"} that digest to vault records; secrets never ride step options, variables or plan texts, only the vault holds them.` };
10574
+ if (input.carries) return { allowed: false, reason: "The step types a raw value into a masked field shape; credential steps read their value from the vault at the last possible moment and never carry it in the options." };
10575
+ return { allowed: true, reason: "The step and the plan carry no secret outside the vault; the values stay behind the seam." };
10576
+ }
10577
+ function untrustedrendergate(input) {
10578
+ if (input.environment === "sandboxframe") return { allowed: true, reason: "The extracted markup renders inside the sandboxframe under its nonce with scripts and handlers stripped; the untrusted content never reenters the page context." };
10579
+ return { allowed: false, reason: `The extracted markup grades untrusted and refuses to render inside the ${input.environment}; every untrusted render routes through the sandboxframe.` };
10580
+ }
10581
+ function sitenotesreadgate(input) {
10582
+ if (input.grants.includes(input.origin)) return { allowed: true, reason: `The session granted ${input.origin}, so the site notes of the origin read.` };
10583
+ return { allowed: false, reason: `The session never granted ${input.origin}; the site notes of the origin refuse the read.` };
10584
+ }
10585
+ function sitenoteswritegate(input) {
10586
+ if (!input.consent) return { allowed: false, reason: `The site note write for ${input.origin} needs the explicit consent of the user; no note lands without a reviewed write.` };
10587
+ return { allowed: true, reason: `The user consented to the site note write for ${input.origin}; the note keeps its author provenance and its timestamps.` };
10588
+ }
10589
+ function scratchpadscopegate(input) {
10590
+ if (input.taskid !== input.entrytaskid || input.sessionid !== input.entrysessionid) return { allowed: false, reason: `The scratchpad entry belongs to the task ${input.entrytaskid} of the session ${input.entrysessionid}; the task ${input.taskid} of the session ${input.sessionid} never crosses that boundary.` };
10591
+ return { allowed: true, reason: `The scratchpad entry belongs to the task ${input.taskid} of the session ${input.sessionid} that asks for it.` };
10592
+ }
10593
+ function memoryreadscopegate(input) {
10594
+ if (input.phase === "planning" || input.phase === "prompting") return { allowed: true, reason: `The ${input.phase} phase reads the correction and consent memory so the proposal and the prompt carry the prior decisions.` };
10595
+ return { allowed: false, reason: `The ${input.phase} phase reads no correction or consent memory; the history serves the planning and the prompting alone.` };
10596
+ }
10597
+ function semanticrecallscopegate(input) {
10598
+ if (input.origin === void 0) return { allowed: true, reason: `The recall query names no origin, so it ranks the ${input.scope.length} origin${input.scope.length === 1 ? "" : "s"} of the run scope only.` };
10599
+ if (!input.scope.includes(input.origin)) return { allowed: false, reason: `The recall query asks for ${input.origin} while the run scope holds ${input.scope.length > 0 ? input.scope.join(", ") : "no origin"}; a recall across origins outside the run scope refuses.` };
10600
+ return { allowed: true, reason: `The recall query asks for ${input.origin} inside the run scope; the ranking stays scoped.` };
10601
+ }
10602
+ function summarywindowvalid(window2) {
10603
+ if (window2 === void 0) return { allowed: true, reason: "No runsummary window is configured, so the distillation keeps every step with no fixed cap." };
10604
+ if (!Number.isInteger(window2) || window2 < 0) return { allowed: false, reason: "The runsummary window stays a whole number of steps the user chose; no engine cap exists." };
10605
+ return { allowed: true, reason: `The runsummary window of ${window2} step${window2 === 1 ? "" : "s"} stays the user configured choice; no engine cap exists.` };
10606
+ }
10607
+ function sessionretentionvalid(window2) {
10608
+ if (window2 === void 0) return { allowed: true, reason: "No retention window is configured, so the session store keeps every record forever." };
10609
+ if (!Number.isFinite(window2) || window2 <= 0) return { allowed: false, reason: "The retention window stays a positive user value in milliseconds; no engine boundary expires a record." };
10610
+ return { allowed: true, reason: `The retention window of ${window2} milliseconds stays the user configured choice.` };
10611
+ }
10612
+ function cancelrungate(input) {
10613
+ if (input.rollbackscope === "none") return { allowed: true, reason: `The cancelrun stops the run with no rollback; the ${input.queuedstepids.length} queued step${input.queuedstepids.length === 1 ? "" : "s"} stay as the run left them and the ${input.executedstepids.length} executed step${input.executedstepids.length === 1 ? "" : "s"} stay in the sealed log.` };
10614
+ return { allowed: true, reason: `The cancelrun rolls the ${input.queuedstepids.length} queued step${input.queuedstepids.length === 1 ? "" : "s"} back${input.queuedstepids.length > 0 ? ` (${input.queuedstepids.join(", ")})` : ""} while the ${input.executedstepids.length} executed step${input.executedstepids.length === 1 ? "" : "s"} stay untouched in the sealed log.` };
10615
+ }
10616
+ function retrydispatchgate(input) {
10617
+ if (!input.reviewed) return { allowed: false, reason: `The retry of the step ${input.stepid} passes only through a new reviewed dispatch; an automatic retry never bypasses the review.` };
10618
+ return { allowed: true, reason: `The retry of the step ${input.stepid} dispatches again through the full consent gate chain: the session, the plan and the origin gates all recheck the step.` };
10619
+ }
9926
10620
 
9927
10621
  // progress.ts
9928
10622
  function emptyprogress(planid, now) {
@@ -9945,6 +10639,10 @@ function recordturnaround2(progress, planid, stepid, milliseconds, now) {
9945
10639
  const base = progress && progress.planid === planid ? progress : emptyprogress(planid, now);
9946
10640
  return { ...base, turnarounds: { ...base.turnarounds ?? {}, [stepid]: milliseconds }, updatedat: now };
9947
10641
  }
10642
+ function recordgatewait(progress, planid, stepid, entry, now) {
10643
+ const base = progress && progress.planid === planid ? progress : emptyprogress(planid, now);
10644
+ return { ...base, gatewaits: { ...base.gatewaits ?? {}, [stepid]: entry }, updatedat: now };
10645
+ }
9948
10646
  function iscomplete(progress, plan) {
9949
10647
  if (!progress || progress.planid !== plan.id) return false;
9950
10648
  const required = plan.steps.map((step) => step.id);
@@ -10169,7 +10867,7 @@ function maskexport(record2, shapes) {
10169
10867
  }
10170
10868
 
10171
10869
  // version.ts
10172
- var packageversion = "1.1.61";
10870
+ var packageversion = "1.1.63";
10173
10871
 
10174
10872
  // types.ts
10175
10873
  var protocolversion = packageversion;
@@ -11143,6 +11841,9 @@ function environmentreport(input) {
11143
11841
  ...input.keepalive !== void 0 ? { keepalive: input.keepalive } : {}
11144
11842
  };
11145
11843
  }
11844
+ function transparencyreport(input) {
11845
+ return { version: protocolversion, posture: "denydefault", grants: input.grants, windows: input.windows, connectallow: input.connectallow, permdiffs: input.permdiffs, safedefaults: input.safedefaults, vault: input.vault };
11846
+ }
11146
11847
 
11147
11848
  // capture.ts
11148
11849
  var capturekinds = ["shotview", "shotfullpage", "shotelement", "shotregion", "contactsheet"];
@@ -11646,7 +12347,7 @@ async function readcapabilities() {
11646
12347
  ]);
11647
12348
  return { tabs, downloads, clipboardread, clipboardwrite, reportedat: Date.now() };
11648
12349
  }
11649
- function stepoptions2(step) {
12350
+ function stepoptions4(step) {
11650
12351
  if (!step.options) return {};
11651
12352
  try {
11652
12353
  const parsed = JSON.parse(step.options);
@@ -11659,7 +12360,7 @@ function tabid(step) {
11659
12360
  return Number.parseInt(step.value ?? "", 10);
11660
12361
  }
11661
12362
  async function runbrowseraction(step, sessiontabid, windowid) {
11662
- const options = stepoptions2(step);
12363
+ const options = stepoptions4(step);
11663
12364
  switch (step.kind) {
11664
12365
  case "tablist": {
11665
12366
  const tabs = await chrome.tabs.query({});
@@ -12285,6 +12986,200 @@ function endcall(input) {
12285
12986
  return { contexts: input.contexts.map((candidate) => candidate.callid === input.callid ? context : candidate), context };
12286
12987
  }
12287
12988
 
12989
+ // sessioninterface.ts
12990
+ function textfingerprint(text2) {
12991
+ let hash = 2166136261;
12992
+ for (let index = 0; index < text2.length; index += 1) {
12993
+ hash ^= text2.charCodeAt(index);
12994
+ hash = Math.imul(hash, 16777619) >>> 0;
12995
+ }
12996
+ return hash.toString(16).padStart(8, "0");
12997
+ }
12998
+ function keystreambyte(id, position) {
12999
+ let hash = 2166136261;
13000
+ const source = `${id}:${position}`;
13001
+ for (let index = 0; index < source.length; index += 1) {
13002
+ hash ^= source.charCodeAt(index);
13003
+ hash = Math.imul(hash, 16777619) >>> 0;
13004
+ }
13005
+ return hash & 255;
13006
+ }
13007
+ function sealnotebody(id, body) {
13008
+ const sealed = Array.from(body, (character, index) => String.fromCharCode(character.charCodeAt(0) ^ keystreambyte(id, index))).join("");
13009
+ return `sealed:${btoa(sealed)}`;
13010
+ }
13011
+ function opennotebody(id, sealedbody) {
13012
+ if (!sealedbody.startsWith("sealed:")) return "";
13013
+ try {
13014
+ const sealed = atob(sealedbody.slice("sealed:".length));
13015
+ return Array.from(sealed, (character, index) => String.fromCharCode(character.charCodeAt(0) ^ keystreambyte(id, index))).join("");
13016
+ } catch {
13017
+ return "";
13018
+ }
13019
+ }
13020
+ function sitenoteof(input) {
13021
+ if (input.origin.trim() === "") throw new Error("The site note needs its origin.");
13022
+ if (input.title.trim() === "") throw new Error("The site note needs its title.");
13023
+ if (input.body.trim() === "") throw new Error("The site note needs its body.");
13024
+ const id = input.id ?? randomid();
13025
+ if (input.sensitive === true) return { id, origin: input.origin, title: input.title.trim(), sealedbody: sealnotebody(id, input.body), author: input.author, sensitive: true, createdat: input.now, updatedat: input.now };
13026
+ return { id, origin: input.origin, title: input.title.trim(), body: input.body, author: input.author, sensitive: false, createdat: input.now, updatedat: input.now };
13027
+ }
13028
+ function notebodyof(note) {
13029
+ if (note.sensitive) return note.sealedbody !== void 0 ? opennotebody(note.id, note.sealedbody) : "";
13030
+ return note.body ?? "";
13031
+ }
13032
+ function editnote(note, input) {
13033
+ if (input.title.trim() === "") throw new Error("The site note keeps a non empty title.");
13034
+ if (input.body.trim() === "") throw new Error("The site note keeps a non empty body.");
13035
+ if (note.sensitive) return { ...note, title: input.title.trim(), sealedbody: sealnotebody(note.id, input.body), updatedat: input.now, author: input.author };
13036
+ return { ...note, title: input.title.trim(), body: input.body, updatedat: input.now, author: input.author };
13037
+ }
13038
+ function scratchentryof(input) {
13039
+ if (input.taskid.trim() === "") throw new Error("The scratchpad entry needs its task.");
13040
+ if (input.text.trim() === "") throw new Error("The scratchpad entry needs its text.");
13041
+ return { id: input.id ?? randomid(), taskid: input.taskid, sessionid: input.sessionid, text: input.text, ...input.stepid !== void 0 && input.stepid.trim() !== "" ? { stepid: input.stepid } : {}, author: input.author, at: input.now };
13042
+ }
13043
+ function distillrunsummary(input) {
13044
+ const steps = input.outcomes.map((outcome) => {
13045
+ const step = input.plan.steps.find((candidate) => candidate.id === outcome.stepid);
13046
+ return { stepid: outcome.stepid, kind: step?.kind ?? "unknown", ok: outcome.ok, summary: outcome.summary };
13047
+ });
13048
+ const windowed = input.window !== void 0 && Number.isInteger(input.window) && input.window >= 0 ? steps.slice(Math.max(0, steps.length - input.window)) : steps;
13049
+ const kinds = [...new Set(windowed.map((step) => step.kind))];
13050
+ return { runid: input.plan.id, sessionid: input.sessionid, origins: [...new Set(input.origins)], kinds, steps: windowed, ...input.window !== void 0 && Number.isInteger(input.window) && input.window >= 0 ? { window: input.window } : {}, task: "runsummary", provenance: input.provenance, distilledat: input.now };
13051
+ }
13052
+ function summaryhistoryentry(summary) {
13053
+ return { source: "summary", id: summary.runid, title: `Run summary of ${summary.runid}`, text: `${summary.origins.join(" ")} ${summary.kinds.join(" ")} ${summary.steps.map((step) => step.summary).join(" ")}`, outcome: summary.steps.every((step) => step.ok) ? "completed" : "failed", at: summary.distilledat };
13054
+ }
13055
+ function notehistoryentry(note) {
13056
+ return { source: "note", id: note.id, ...note.origin !== "" ? { origin: note.origin } : {}, title: note.title, text: note.sensitive ? note.title : `${note.title} ${note.body ?? ""}`, at: note.updatedat };
13057
+ }
13058
+ function recallentryof(input) {
13059
+ if (input.text.trim() === "") throw new Error("The recall index entry needs its text.");
13060
+ if (input.stepid.trim() === "" || input.runid.trim() === "") throw new Error("The recall index entry needs its run and step provenance.");
13061
+ const normalized = input.text.trim().replace(/\s+/g, " ");
13062
+ return { fingerprint: textfingerprint(normalized), origin: input.origin, runid: input.runid, stepid: input.stepid, text: normalized, at: input.at };
13063
+ }
13064
+ function termsof(text2) {
13065
+ return new Set(text2.toLowerCase().split(/[^a-z0-9]+/).filter((term) => term.length > 1));
13066
+ }
13067
+ function rankrecall(index, query, scope) {
13068
+ if (query.text.trim() === "") return [];
13069
+ const terms = termsof(query.text);
13070
+ const scoped = query.origin !== void 0 && query.origin.trim() !== "" ? [query.origin] : scope.origins;
13071
+ const matches = [];
13072
+ for (const entry of index) {
13073
+ if (!scoped.includes(entry.origin)) continue;
13074
+ const entryterms = termsof(entry.text);
13075
+ let shared = 0;
13076
+ for (const term of terms) if (entryterms.has(term)) shared += 1;
13077
+ const union = (/* @__PURE__ */ new Set([...terms, ...entryterms])).size;
13078
+ const score = union === 0 ? 0 : shared / union;
13079
+ if (score <= 0) continue;
13080
+ matches.push({ entry, score, reason: `The extraction of ${entry.origin} shares ${shared} term${shared === 1 ? "" : "s"} with the query at the score ${score.toFixed(3)}; the match carries the run ${entry.runid} and the step ${entry.stepid}.` });
13081
+ }
13082
+ const ranked = matches.sort((one, two) => two.score - one.score);
13083
+ return query.limit !== void 0 && Number.isInteger(query.limit) && query.limit >= 0 ? ranked.slice(0, query.limit) : ranked;
13084
+ }
13085
+ function editedcorrectionof(input) {
13086
+ if (input.stepid.trim() === "" || input.kind.trim() === "") throw new Error("The correction needs its step and kind.");
13087
+ if (input.original === input.corrected) throw new Error("The correction needs a changed step shape.");
13088
+ return { id: input.id ?? randomid(), origin: input.origin, kind: input.kind, stepid: input.stepid, source: "edited", original: input.original, corrected: input.corrected, reason: input.reason, at: input.now };
13089
+ }
13090
+ function rejectedcorrectionof(input) {
13091
+ if (input.stepid.trim() === "" || input.reason.trim() === "") throw new Error("The rejected correction needs its step and its rejection reason.");
13092
+ return { id: input.id ?? randomid(), origin: input.origin, kind: input.kind, stepid: input.stepid, source: "rejected", original: input.original, reason: input.reason, at: input.now };
13093
+ }
13094
+ function consentmemoryof(input) {
13095
+ if (input.origin.trim() === "") throw new Error("The consent memory entry needs its origin.");
13096
+ if (input.boundary.trim() === "") throw new Error("The consent memory entry needs the boundary the prompt named.");
13097
+ return { id: input.id ?? randomid(), origin: input.origin, decision: input.decision, boundary: input.boundary, kinds: [...new Set(input.kinds)], at: input.now, ...input.expiresat !== void 0 ? { expiresat: input.expiresat } : {} };
13098
+ }
13099
+ function consentadvisoryverdict(entries, origin, kind) {
13100
+ const matching = entries.filter((entry) => entry.origin === origin && entry.kinds.includes(kind));
13101
+ const latest = matching[matching.length - 1];
13102
+ if (latest === void 0) return { advisory: false, reason: `No prior decision exists for the ${kind} kind on ${origin}; the prompt opens fresh.` };
13103
+ if (latest.decision === "deny") return { advisory: true, reason: `The consent memory holds a prior denial of the ${kind} kind on ${origin} from ${new Date(latest.at).toISOString()}; the denial carries the same weight as a grant and the record stays advisory only.` };
13104
+ return { advisory: true, reason: `The consent memory holds a prior ${latest.decision} of the ${kind} kind on ${origin} with the boundary ${latest.boundary}; the record advises the new prompt and never auto grants.` };
13105
+ }
13106
+ function rollbacksplit(plan, progress) {
13107
+ const executed = progress && progress.planid === plan?.id ? progress.completedsteps : [];
13108
+ const executedset = new Set(executed);
13109
+ const queued = (plan?.steps ?? []).map((step) => step.id).filter((id) => !executedset.has(id));
13110
+ return { executedstepids: executed, queuedstepids: queued };
13111
+ }
13112
+ function rollbackof(plan, progress, preference) {
13113
+ const split = rollbacksplit(plan, progress);
13114
+ if (preference === "none") return { scope: "none", label: `Stop the run ${plan?.id ?? ""} without a rollback; the ${split.queuedstepids.length} queued step${split.queuedstepids.length === 1 ? "" : "s"} stay as the run left them.`, queuedstepids: split.queuedstepids };
13115
+ return { scope: "queued", label: `Cancel the run ${plan?.id ?? ""} and roll its ${split.queuedstepids.length} queued step${split.queuedstepids.length === 1 ? "" : "s"} back${split.queuedstepids.length > 0 ? ` (${split.queuedstepids.join(", ")})` : ""} while the ${split.executedstepids.length} executed step${split.executedstepids.length === 1 ? "" : "s"} stay untouched in the sealed log.`, queuedstepids: split.queuedstepids };
13116
+ }
13117
+ function cancelrunactionof(input) {
13118
+ return { runid: input.runid, sessionid: input.sessionid, rollback: rollbackof(input.plan, input.progress, input.preference) };
13119
+ }
13120
+ function errorsurfaceof(input) {
13121
+ if (input.message.trim() === "") throw new Error("The error surface needs its message in plain language.");
13122
+ return { stepid: input.stepid, runid: input.runid, cause: input.cause, message: input.message, retry: { allowed: input.retryallowed, reason: input.retryreason }, context: input.context, at: input.now };
13123
+ }
13124
+ function classifyfailure(input) {
13125
+ if (input.gatewait) return "gate";
13126
+ if (input.policyrefused) return "policy";
13127
+ if (/\b(network|offline|timeout|timed out|fetch failed|socket|dns|connection)\b/i.test(input.message)) return "network";
13128
+ return "page";
13129
+ }
13130
+ function sessiongridrows(input) {
13131
+ const rows = [];
13132
+ if (input.session && input.plan && ["pending", "approved"].includes(input.plan.state)) {
13133
+ const split = rollbacksplit(input.plan, input.progress);
13134
+ const held = input.locks.some((lock) => lock.runid === input.plan?.id);
13135
+ const origins = [.../* @__PURE__ */ new Set([input.session.origin, ...input.session.grants ?? []])];
13136
+ const actions = ["cancelrun"];
13137
+ if (input.session.pausedat !== void 0) actions.push("resume");
13138
+ rows.push({ sessionid: input.session.id, runid: input.plan.id, origins, state: "live", outcome: `${split.executedstepids.length} of ${input.plan.steps.length} reviewed steps executed`, steps: input.plan.steps.length, completed: split.executedstepids.length, lock: held ? "held" : "free", tabid: input.session.tabid, updatedat: input.plan.createdat, actions });
13139
+ }
13140
+ for (const log of input.logs) {
13141
+ const summary = input.summaries.find((candidate) => candidate.runid === log.runid);
13142
+ const tabsession = input.tabsessions.find((candidate) => candidate.runid === log.runid);
13143
+ const held = input.locks.some((lock) => lock.runid === log.runid);
13144
+ rows.push({ sessionid: log.sessionid, runid: log.runid, origins: [...new Set(log.entries.map((entry) => entry.origin).filter((origin) => origin !== ""))], state: "saved", outcome: summary !== void 0 ? summary.steps.every((step) => step.ok) ? "completed" : "failed" : log.seal !== void 0 ? "sealed" : "open", steps: summary?.steps.length ?? log.entries.filter((entry) => entry.kind === "step").length, completed: summary?.steps.filter((step) => step.ok).length ?? log.entries.filter((entry) => entry.kind === "step").length, lock: held ? "held" : "free", ...log.seal !== void 0 ? { sealhash: log.seal.sealhash.current } : {}, ...tabsession !== void 0 ? { tabid: tabsession.tabid } : {}, updatedat: log.updatedat, actions: ["reopen"] });
13145
+ }
13146
+ return rows.sort((one, two) => two.updatedat - one.updatedat);
13147
+ }
13148
+ function historyqueryof(value) {
13149
+ if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
13150
+ const candidate = value;
13151
+ if (typeof candidate.text !== "string" || candidate.text.trim() === "") return void 0;
13152
+ const origin = typeof candidate.origin === "string" && candidate.origin.trim() !== "" ? candidate.origin.trim() : void 0;
13153
+ const from = typeof candidate.from === "number" && Number.isFinite(candidate.from) ? candidate.from : void 0;
13154
+ const to = typeof candidate.to === "number" && Number.isFinite(candidate.to) ? candidate.to : void 0;
13155
+ if (from !== void 0 && to !== void 0 && from > to) return void 0;
13156
+ const outcome = typeof candidate.outcome === "string" && candidate.outcome.trim() !== "" ? candidate.outcome.trim() : void 0;
13157
+ return { text: candidate.text.trim(), ...origin !== void 0 ? { origin } : {}, ...from !== void 0 ? { from } : {}, ...to !== void 0 ? { to } : {}, ...outcome !== void 0 ? { outcome } : {} };
13158
+ }
13159
+ function historysearch(corpus, query) {
13160
+ const terms = query.text.toLowerCase().split(/[^a-z0-9]+/).filter((term) => term.length > 1);
13161
+ const hits = [];
13162
+ for (const entry of corpus) {
13163
+ if (query.origin !== void 0 && entry.origin !== query.origin) continue;
13164
+ if (query.from !== void 0 && entry.at < query.from) continue;
13165
+ if (query.to !== void 0 && entry.at > query.to) continue;
13166
+ if (query.outcome !== void 0 && entry.outcome !== query.outcome) continue;
13167
+ const haystack = `${entry.title} ${entry.text}`.toLowerCase();
13168
+ const matched = terms.filter((term) => haystack.includes(term));
13169
+ if (matched.length === 0) continue;
13170
+ const position = haystack.indexOf(matched[0] ?? "");
13171
+ const start = Math.max(0, position - 40);
13172
+ const excerpt = `${start > 0 ? "\u2026" : ""}${`${entry.title} ${entry.text}`.slice(start, start + 160)}${start + 160 < `${entry.title} ${entry.text}`.length ? "\u2026" : ""}`;
13173
+ hits.push({ source: entry.source, id: entry.id, title: entry.title, excerpt, highlights: [...new Set(matched)], ...entry.origin !== void 0 ? { origin: entry.origin } : {}, ...entry.outcome !== void 0 ? { outcome: entry.outcome } : {}, at: entry.at });
13174
+ }
13175
+ return hits.sort((one, two) => two.at - one.at);
13176
+ }
13177
+ function tabsessionrefof(input) {
13178
+ if (!Number.isInteger(input.tabid) || input.tabid < 0) throw new Error("The per tab session reference needs its tab.");
13179
+ if (input.sessionid.trim() === "") throw new Error("The per tab session reference needs its session.");
13180
+ return { tabid: input.tabid, sessionid: input.sessionid, ...input.runid !== void 0 && input.runid.trim() !== "" ? { runid: input.runid } : {}, origin: input.origin, updatedat: input.now };
13181
+ }
13182
+
12288
13183
  // llm.ts
12289
13184
  var defaultrefusalmarkers = ["i cannot", "i can't", "i'm unable", "refusal:", "cannot comply"];
12290
13185
  function buildrequest(input) {
@@ -13119,6 +14014,144 @@ function acceptrenderresult(input) {
13119
14014
  return { accepted: true, result, reason: `The render result of the step ${render.stepid} answers the nonce of its render; the text stays inside the frame.` };
13120
14015
  }
13121
14016
 
14017
+ // secretvault.ts
14018
+ var vaultdigestprefix = "sha256:";
14019
+ async function vaultdigestof(value) {
14020
+ const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(value));
14021
+ return vaultdigestprefix + [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, "0")).join("");
14022
+ }
14023
+ function vaultentryof(input) {
14024
+ if (input.label.trim() === "") throw new Error("The vault record needs its label; the surfaces show the label only.");
14025
+ if (input.scope.trim() === "") throw new Error("The vault record needs its exact origin scope; a secret never rides every origin.");
14026
+ if (!input.digest.startsWith(vaultdigestprefix)) throw new Error("The vault record carries its sha-256 digest, never its value.");
14027
+ return { vaultid: input.vaultid ?? randomid(), label: input.label.trim(), scope: input.scope.trim(), profileid: input.profileid, provenance: input.provenance, algorithm: "sha-256", digest: input.digest, createdat: input.now };
14028
+ }
14029
+ function inmemoryvault() {
14030
+ const values = /* @__PURE__ */ new Map();
14031
+ return {
14032
+ put: async (vaultid, value) => {
14033
+ values.set(vaultid, value);
14034
+ },
14035
+ fetch: async (vaultid) => values.get(vaultid),
14036
+ drop: async (vaultid) => {
14037
+ values.delete(vaultid);
14038
+ }
14039
+ };
14040
+ }
14041
+ async function vaultstore(input) {
14042
+ if (input.value === "") throw new Error("The vault stores a secret value the user supplied; an empty value stores nothing.");
14043
+ const entry = vaultentryof({ label: input.label, scope: input.scope, profileid: input.profileid, provenance: input.provenance, digest: await vaultdigestof(input.value), now: input.now });
14044
+ await input.seam.put(entry.vaultid, input.value);
14045
+ return entry;
14046
+ }
14047
+ async function vaultvaluefor(input) {
14048
+ const value = await input.seam.fetch(input.entry.vaultid);
14049
+ if (value === void 0) return { ok: false, reason: `The vault holds no value behind the label ${input.entry.label}; add the secret again.` };
14050
+ return { ok: true, value, reason: `The vault released the value behind the label ${input.entry.label} at the last possible moment; the value reaches the credential field only and no log records it.` };
14051
+ }
14052
+ async function vaultdelete(input) {
14053
+ await input.seam.drop(input.entry.vaultid);
14054
+ return { dropped: true, label: input.entry.label, reason: `The vault dropped the secret ${input.entry.label} of ${input.entry.scope}; no value and no copy remains behind the seam.` };
14055
+ }
14056
+ async function secretleakscan(input) {
14057
+ const leaks = [];
14058
+ for (const candidate of input.candidates) {
14059
+ if (candidate.trim() === "") continue;
14060
+ const digest = await vaultdigestof(candidate);
14061
+ if (input.entries.some((entry) => entry.digest === digest)) leaks.push(candidate);
14062
+ }
14063
+ if (leaks.length > 0) return { leaks, reason: `The plan carries ${leaks.length} plaintext value${leaks.length === 1 ? "" : "s"} that digest to vault records; secrets never ride step options, variables or plan texts, only the vault holds them.` };
14064
+ return { leaks: [], reason: "No candidate value digests to a vault record; the plan carries no leaked secret." };
14065
+ }
14066
+ function stepoptions5(step) {
14067
+ if (!step.options) return {};
14068
+ try {
14069
+ const parsed = JSON.parse(step.options);
14070
+ return Boolean(parsed) && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
14071
+ } catch {
14072
+ return {};
14073
+ }
14074
+ }
14075
+ function secretshapecarrying(step) {
14076
+ const options = stepoptions5(step);
14077
+ const fields = Array.isArray(options.fields) ? options.fields.filter((item) => Boolean(item) && typeof item === "object") : [];
14078
+ const rawfield = fields.find((field) => typeof field.name === "string" && typeof field.value === "string" && field.value !== "" && maskingfield(field.name, []));
14079
+ if (rawfield !== void 0) return { carries: true, reason: `The ${step.kind} step types a raw value into the ${String(rawfield.name)} field; credential steps read their value from the vault at the last possible moment and never carry it in the options.` };
14080
+ if (typeof options.field === "string" && maskingfield(options.field, []) && step.value !== void 0 && step.value !== "") return { carries: true, reason: `The ${step.kind} step types a raw value into the ${options.field} field; credential steps read their value from the vault at the last possible moment and never carry it in the options.` };
14081
+ return { carries: false, reason: "The step carries no raw value behind a masked field shape." };
14082
+ }
14083
+ function vaultview(entries) {
14084
+ return entries.map((entry) => ({ vaultid: entry.vaultid, label: entry.label, scope: entry.scope, provenance: entry.provenance, createdat: entry.createdat, ...entry.lastusedat !== void 0 ? { lastusedat: entry.lastusedat } : {} }));
14085
+ }
14086
+
14087
+ // redactshots.ts
14088
+ function regionof(input) {
14089
+ if (input.origin.trim() === "" || input.template.trim() === "") throw new Error("The redact region needs its origin and its page template.");
14090
+ for (const value of [input.x, input.y, input.width, input.height]) {
14091
+ if (!Number.isFinite(value) || value < 0) throw new Error("The redact region needs finite, non-negative geometry in css pixels.");
14092
+ }
14093
+ if (input.width <= 0 || input.height <= 0) throw new Error("The redact region needs a positive width and height so the mask covers a real area.");
14094
+ if (input.reason.trim() === "") throw new Error("The redact region names its reason in plain language.");
14095
+ return { id: input.id ?? randomid(), origin: input.origin.trim(), template: input.template.trim(), x: input.x, y: input.y, width: input.width, height: input.height, reason: input.reason.trim(), source: input.source, createdat: input.now };
14096
+ }
14097
+ function regionsfor(regions, origin, template) {
14098
+ return regions.filter((region) => region.origin === origin && region.template === template);
14099
+ }
14100
+ function templateof(step) {
14101
+ if (step.options) {
14102
+ try {
14103
+ const parsed = JSON.parse(step.options);
14104
+ if (Boolean(parsed) && typeof parsed === "object" && !Array.isArray(parsed)) {
14105
+ const template = parsed.template;
14106
+ if (typeof template === "string" && template.trim() !== "") return template.trim();
14107
+ }
14108
+ } catch {
14109
+ }
14110
+ }
14111
+ return step.kind;
14112
+ }
14113
+ function redactedshot(record2, regions) {
14114
+ if (regions.length === 0) return record2;
14115
+ return { ...record2, redacted: true, redactedregions: regions.length };
14116
+ }
14117
+ function redactionsummary(regions) {
14118
+ if (regions.length === 0) return "No redact region covered the capture; the stored bytes carry everything the surface saw.";
14119
+ const sources = { fieldshape: 0, userdrawn: 0 };
14120
+ for (const region of regions) sources[region.source] += 1;
14121
+ return `${regions.length} redact region${regions.length === 1 ? "" : "s"} covered the capture before storage: ${sources.fieldshape} derived from sensitive field shapes and ${sources.userdrawn} drawn by the user (${regions.map((region) => region.reason).join("; ")}).`;
14122
+ }
14123
+
14124
+ // transparency.ts
14125
+ function permissiondiff(input) {
14126
+ if (input.fromversion.trim() === "" || input.toversion.trim() === "") throw new Error("The permdiff names the two versions it compares.");
14127
+ const added = [...new Set(input.to.filter((permission) => !input.from.includes(permission)))];
14128
+ const removed = [...new Set(input.from.filter((permission) => !input.to.includes(permission)))];
14129
+ return { fromversion: input.fromversion, toversion: input.toversion, added, removed, computedat: input.now };
14130
+ }
14131
+ function permdiffchanged(diff) {
14132
+ return diff.added.length > 0 || diff.removed.length > 0;
14133
+ }
14134
+ function permdiffsummary(diff) {
14135
+ if (!permdiffchanged(diff)) return `The update from ${diff.fromversion} to ${diff.toversion} changed no permission.`;
14136
+ const parts = [];
14137
+ if (diff.added.length > 0) parts.push(`added ${diff.added.join(", ")}`);
14138
+ if (diff.removed.length > 0) parts.push(`removed ${diff.removed.join(", ")}`);
14139
+ return `The update from ${diff.fromversion} to ${diff.toversion} ${parts.join(" and ")}.`;
14140
+ }
14141
+ function transparencygrants(input) {
14142
+ const grants = input.allowlist.map((entry) => ({ origin: entry.origin, scope: `automation allowlist of the profile workspace ${entry.profileid}`, boundary: "the user revokes the entry or the profile workspace", grantedat: entry.grantedat }));
14143
+ for (const profile of input.profiles) {
14144
+ grants.push({ origin: profile.origin, scope: `origin profile with ${profile.grants.length} granted and ${profile.denials.length} denied kinds`, boundary: "the user edits or revokes the profile", grantedat: profile.createdat });
14145
+ }
14146
+ return grants;
14147
+ }
14148
+ function windowhistory(windows) {
14149
+ return windows.map((window2) => ({ id: window2.id, origin: window2.origin, state: window2.state, boundary: window2.boundary, startedat: window2.startedat, expiresat: window2.expiresat }));
14150
+ }
14151
+ function connectallowlist(entries) {
14152
+ return entries.map((entry) => ({ senderid: entry.senderid, displayname: entry.displayname, ...entry.origin !== void 0 ? { origin: entry.origin } : {}, addedat: entry.addedat }));
14153
+ }
14154
+
13122
14155
  // modelroute.ts
13123
14156
  function routevalid(route) {
13124
14157
  if (route.kind.trim() === "") return { allowed: false, reason: "The model route needs its task kind." };
@@ -14325,13 +15358,28 @@ var chromestorage = {
14325
15358
  }
14326
15359
  };
14327
15360
  var memory = new sessionmemory(chromestorage);
15361
+ var vaultseamstore = (() => {
15362
+ const session = chrome.storage?.session;
15363
+ if (session) {
15364
+ return {
15365
+ put: async (vaultid, value) => {
15366
+ await session.set({ [`vault:${vaultid}`]: value });
15367
+ },
15368
+ fetch: async (vaultid) => (await session.get(`vault:${vaultid}`))[`vault:${vaultid}`],
15369
+ drop: async (vaultid) => {
15370
+ await session.remove(`vault:${vaultid}`);
15371
+ }
15372
+ };
15373
+ }
15374
+ return inmemoryvault();
15375
+ })();
14328
15376
  function extensionpage(sender) {
14329
15377
  return sender.id === chrome.runtime.id && Boolean(sender.url?.startsWith(chrome.runtime.getURL("")));
14330
15378
  }
14331
15379
  async function audit(kind, summary, extra = {}) {
14332
15380
  await memory.addaudi({ id: randomid(), kind, at: Date.now(), summary, ...extra });
14333
15381
  }
14334
- function stepoptions3(step) {
15382
+ function stepoptions6(step) {
14335
15383
  try {
14336
15384
  return parseoptions(step);
14337
15385
  } catch {
@@ -14556,6 +15604,12 @@ async function securitystepgate(step, session, origin, settings) {
14556
15604
  const allowverdict = automationallowlistgate({ origin, allowlist: await memory.getautomationallowlist(), session });
14557
15605
  if (!allowverdict.allowed) return { allowed: false, suspended: false, reason: allowverdict.reason ?? "", classification };
14558
15606
  const profile = (await memory.getoriginprofiles()).find((candidate) => candidate.origin === origin);
15607
+ if (profile === void 0) {
15608
+ await memory.addsafedefaultapplication({ origin, firstseenat: now }).catch(() => {
15609
+ });
15610
+ const safedefaultverdict = safedefaultsgate({ profile, classes: classification.classes, sensitive: classification.sensitive });
15611
+ if (!safedefaultverdict.allowed) return { allowed: false, suspended: false, reason: safedefaultverdict.reason ?? "", classification };
15612
+ }
14559
15613
  const profileverdict = originprofilegate({ profile, kind: step.kind, sensitive: classification.sensitive });
14560
15614
  if (!profileverdict.allowed) return { allowed: false, suspended: false, reason: profileverdict.reason ?? "", classification };
14561
15615
  const windows = await memory.expireconsentwindows(now);
@@ -14568,8 +15622,115 @@ async function securitystepgate(step, session, origin, settings) {
14568
15622
  const revocation = plan === void 0 ? void 0 : (await memory.getrevocations()).find((candidate) => candidate.sessionid === session.id && candidate.runid === plan.id);
14569
15623
  const revokeverdict = revokerungate({ revocation, sessionid: session.id, runid: plan?.id ?? "" });
14570
15624
  if (!revokeverdict.allowed) return { allowed: false, suspended: false, reason: revokeverdict.reason ?? "", classification };
15625
+ const confirmverdict = await confirmgatechain(step, session, plan, origin, classification, now);
15626
+ if (confirmverdict !== void 0) return { allowed: confirmverdict.allowed, suspended: false, reason: confirmverdict.reason, classification };
14571
15627
  return { allowed: true, suspended: false, reason: `${classification.reason} ${allowverdict.reason ?? ""} ${windowverdict.reason ?? ""} ${consentverdict.reason ?? ""}`, classification };
14572
15628
  }
15629
+ async function confirmgatechain(step, session, plan, origin, classification, now) {
15630
+ if (!session || !plan) return void 0;
15631
+ const kind = gatekindfor(classification.classes);
15632
+ if (kind !== void 0) {
15633
+ const gates = await memory.getgates();
15634
+ const state = gatestateof(gates, step.id);
15635
+ if (state.state === "none") {
15636
+ const vaultentries2 = await memory.getsecretvault();
15637
+ const vaultlabel = vaultentries2.find((entry) => entry.scope === origin)?.label;
15638
+ const gate = gateforstep({ step, classes: classification.classes, runid: plan.id, origin, credentiallabel: vaultlabel ?? `the credential the ${step.kind} step reviews`, now });
15639
+ if (gate) {
15640
+ await memory.savegate(gate);
15641
+ await appendrunevent("gate", `The ${gate.kind} gate opened for the ${step.kind} step ${step.id} on ${origin}: ${gateprompttext(gate)}`, session, origin, step.id).catch(() => {
15642
+ });
15643
+ await audit("gate", `The ${gate.kind} gate opened for the ${step.kind} step ${step.id} on ${origin}; the executor pauses until one distinct human action resolves it and no timeout ever resolves a gate.`, { sessionid: session.id, planid: plan.id, stepid: step.id });
15644
+ return { allowed: false, reason: `The ${gate.kind} gate opened for the ${step.kind} step ${step.id} on ${origin}: ${gateprompttext(gate)} The executor pauses until the human resolves it.` };
15645
+ }
15646
+ }
15647
+ const gateverdict = kind === "confirmpay" ? confirmpaygate({ classes: classification.classes, state: state.state }) : kind === "confirmdelete" ? confirmdeletegate({ classes: classification.classes, state: state.state }) : confirmcredsgate({ classes: classification.classes, state: state.state });
15648
+ if (!gateverdict.allowed) return { allowed: false, reason: gateverdict.reason ?? "" };
15649
+ if (state.state === "resolved" && state.gate !== void 0 && state.gate.resolvedat !== void 0) {
15650
+ await memory.setprogress(recordgatewait(await memory.getprogress(), plan.id, step.id, { gateid: state.gate.gateid, kind: state.gate.kind, openedat: state.gate.openedat, resolvedat: state.gate.resolvedat, waitedms: Math.max(0, state.gate.resolvedat - state.gate.openedat) }, now)).catch(() => {
15651
+ });
15652
+ }
15653
+ }
15654
+ if (credentialstep(step)) {
15655
+ const settings = await memory.getsettings();
15656
+ const threshold = settings?.phishdistance;
15657
+ if (threshold !== void 0) {
15658
+ const thresholdgate = phishthresholdgate(threshold);
15659
+ if (!thresholdgate.allowed) return { allowed: false, reason: thresholdgate.reason ?? "" };
15660
+ const live = await memory.expirephishverdicts(settings?.phishfreshness, now);
15661
+ const stored = live.find((verdict2) => verdict2.origin === origin);
15662
+ const verdict = stored ?? phishverdictof({ origin, granted: [.../* @__PURE__ */ new Set([...(await memory.getautomationallowlist()).map((entry) => entry.origin), session.origin])], threshold, now });
15663
+ if (stored === void 0) await memory.addphishverdict(verdict);
15664
+ const phishgate = phishguardgate({ verdict });
15665
+ if (!phishgate.allowed) {
15666
+ await appendrunevent("phish", `The phishguard blocked the credential step ${step.id} on ${origin}: ${verdict.reason}`, session, origin, step.id).catch(() => {
15667
+ });
15668
+ await audit("phish", `The phishguard blocked the ${step.kind} step ${step.id} on ${origin}: ${verdict.reason}`, { sessionid: session.id, planid: plan.id, stepid: step.id });
15669
+ return { allowed: false, reason: phishgate.reason ?? "" };
15670
+ }
15671
+ }
15672
+ }
15673
+ const buckets = await memory.getratelimitbuckets();
15674
+ const bucket = buckets.find((candidate) => candidate.origin === origin && candidate.sessionid === session.id);
15675
+ if (bucket !== void 0) {
15676
+ const consumed = bucketconsume({ bucket, now });
15677
+ if (!consumed.allowed) {
15678
+ const deferred = deferredeventof({ stepid: step.id, kind: step.kind, origin, reason: consumed.reason, resetsat: consumed.resetsat, now });
15679
+ await memory.adddeferredevent(deferred);
15680
+ await appendrunevent("suspend", `The ratelimit bucket of ${origin} deferred the ${step.kind} step ${step.id} until the window resets at ${deferred.resetsat}: ${consumed.reason}`, session, origin, step.id).catch(() => {
15681
+ });
15682
+ await audit("defer", `The ratelimit bucket of ${origin} deferred the ${step.kind} step ${step.id} until the window resets at ${deferred.resetsat}; the bounds stay user configured choices with no hidden ceiling.`, { sessionid: session.id, planid: plan.id, stepid: step.id });
15683
+ return { allowed: false, reason: consumed.reason };
15684
+ }
15685
+ await memory.saveratelimitbucket(consumed.bucket);
15686
+ }
15687
+ const vaultentries = await memory.getsecretvault();
15688
+ const options = stepoptions6(step);
15689
+ const candidates = [step.value ?? "", ...Object.values(options).filter((value) => typeof value === "string")];
15690
+ const leakscan = await secretleakscan({ candidates, entries: vaultentries });
15691
+ const secretverdict = vaultsecretgate({ leaks: leakscan.leaks, carries: secretshapecarrying(step).carries });
15692
+ if (!secretverdict.allowed) {
15693
+ await audit("vault", `The vault secret scan refused the ${step.kind} step ${step.id} on ${origin}: ${secretverdict.reason}`, { sessionid: session.id, planid: plan.id, stepid: step.id });
15694
+ return { allowed: false, reason: secretverdict.reason ?? "" };
15695
+ }
15696
+ return void 0;
15697
+ }
15698
+ async function resolvevaultvalues(step, session) {
15699
+ void session;
15700
+ const marker = /^vault:[A-Za-z0-9-]+$/;
15701
+ if (step.options === void 0 || !step.options.includes("vault:")) return step;
15702
+ const entries = await memory.getsecretvault();
15703
+ let options = step.options;
15704
+ try {
15705
+ const parsed = JSON.parse(step.options);
15706
+ if (Boolean(parsed) && typeof parsed === "object" && !Array.isArray(parsed)) {
15707
+ const record2 = parsed;
15708
+ const resolvevalue = async (value) => {
15709
+ if (!marker.test(value)) return value;
15710
+ const entry = entries.find((candidate) => candidate.vaultid === value.slice("vault:".length));
15711
+ if (!entry) return value;
15712
+ const fetched = await vaultvaluefor({ seam: vaultseamstore, entry });
15713
+ if (fetched.ok && fetched.value !== void 0) {
15714
+ await memory.stampsecretuse(entry.vaultid, Date.now());
15715
+ return fetched.value;
15716
+ }
15717
+ return value;
15718
+ };
15719
+ for (const [key, value] of Object.entries(record2)) if (typeof value === "string") record2[key] = await resolvevalue(value);
15720
+ if (Array.isArray(record2.fields)) {
15721
+ for (const field of record2.fields) {
15722
+ if (!Boolean(field) || typeof field !== "object" || Array.isArray(field)) continue;
15723
+ const fieldrecord = field;
15724
+ if (typeof fieldrecord.value === "string") fieldrecord.value = await resolvevalue(fieldrecord.value);
15725
+ }
15726
+ }
15727
+ options = JSON.stringify(record2);
15728
+ }
15729
+ } catch {
15730
+ }
15731
+ if (options === step.options) return step;
15732
+ return { ...step, options };
15733
+ }
14573
15734
  async function sealsessionrunlog(sessionid) {
14574
15735
  const log = await memory.getimmutablelog(sessionid);
14575
15736
  if (!log || log.seal !== void 0 || log.entries.length === 0) return;
@@ -14593,10 +15754,19 @@ async function securityviewof() {
14593
15754
  maskrules: await memory.getmaskrules(),
14594
15755
  chain,
14595
15756
  posture: "denydefault",
15757
+ gates: await memory.getgates(),
15758
+ resolutions: await memory.getgateresolutions(),
15759
+ deferred: await memory.getdeferredevents(),
15760
+ phishverdicts: await memory.getphishverdicts(),
15761
+ vault: await memory.getsecretvault(),
15762
+ connectallow: await memory.getconnectallow(),
15763
+ safedefaults: await memory.getsafedefaultapplications(),
15764
+ redactregions: await memory.getredactregions(),
14596
15765
  ...session ? { sessionorigin: session.origin } : {},
14597
15766
  ...settings?.consentduration !== void 0 ? { promptduration: settings.consentduration } : {},
14598
15767
  ...settings?.logretention !== void 0 ? { logretention: settings.logretention } : {},
14599
- ...settings?.maskshapes !== void 0 ? { maskshapes: settings.maskshapes } : {}
15768
+ ...settings?.maskshapes !== void 0 ? { maskshapes: settings.maskshapes } : {},
15769
+ ...settings?.phishdistance !== void 0 ? { phishdistance: settings.phishdistance } : {}
14600
15770
  };
14601
15771
  }
14602
15772
  async function executeisolatedevaluate(step, tabid2, origin) {
@@ -14618,9 +15788,11 @@ async function executeisolatedevaluate(step, tabid2, origin) {
14618
15788
  return result[0]?.result ?? { ok: false, summary: "The isolated world returned no result." };
14619
15789
  }
14620
15790
  async function executesandboxrender(step, session, plan, origin) {
14621
- const options = stepoptions3(step);
15791
+ const options = stepoptions6(step);
14622
15792
  const markup = typeof options.markup === "string" ? options.markup : "";
14623
15793
  const sourceorigin = typeof options.sourceorigin === "string" ? options.sourceorigin : origin;
15794
+ const rendergate = untrustedrendergate({ environment: "sandboxframe" });
15795
+ if (!rendergate.allowed) throw new Error(rendergate.reason);
14624
15796
  const settings = await memory.getsettings();
14625
15797
  const origingate = sandboxorigingate({ origin: sourceorigin, allowed: settings?.sandboxorigins ?? [] });
14626
15798
  if (!origingate.allowed) throw new Error(origingate.reason);
@@ -14652,7 +15824,7 @@ async function offloadparsetoworker(step, output, session, plan, origin) {
14652
15824
  const ready = await ensureoffscreendocument(runid);
14653
15825
  if (!ready) return { output, turnaround: void 0 };
14654
15826
  const payload = JSON.stringify({ summary: output?.summary ?? "", details: output?.details ?? {} });
14655
- const request = workerrequestof({ id: randomid(), runid, stepid: step.id, kind: step.kind, payload, options: stepoptions3(step), sentat: Date.now() });
15827
+ const request = workerrequestof({ id: randomid(), runid, stepid: step.id, kind: step.kind, payload, options: stepoptions6(step), sentat: Date.now() });
14656
15828
  const started = Date.now();
14657
15829
  let answer;
14658
15830
  try {
@@ -14743,6 +15915,10 @@ async function startsession() {
14743
15915
  const { tab, origin } = await activecontext();
14744
15916
  const session = { id: randomid(), tabid: tab.id, origin, startedat: Date.now(), expiresat: Date.now() + sessionduration, grants: [origin] };
14745
15917
  await memory.setsession(session);
15918
+ await memory.settabsession(tabsessionrefof({ tabid: session.tabid, sessionid: session.id, origin, now: session.startedat }));
15919
+ await memory.tracktabsession(session.tabid);
15920
+ await memory.addconsentmemoryentry(consentmemoryof({ origin, decision: "grant", boundary: `the session expiry at ${new Date(session.expiresat).toISOString()}`, kinds: ["observe"], now: session.startedat }));
15921
+ if ((await memory.getsettings())?.historyindex !== false) await memory.addhistoryentry({ source: "session", id: session.id, origin, title: `Session of ${origin}`, text: `session ${origin} started ${new Date(session.startedat).toISOString()}`, at: session.startedat });
14746
15922
  await memory.addallowlistorigin({ origin, profileid: runstateprofile, grantedat: session.startedat });
14747
15923
  const scope = scopegrantof({ origin, kinds: ["observe"], boundary: `the session expiry at ${new Date(session.expiresat).toISOString()}`, now: session.startedat });
14748
15924
  let runlog = openrunlog({ runid: session.id, sessionid: session.id, now: session.startedat });
@@ -14855,7 +16031,7 @@ function stepauditkind(step, ok) {
14855
16031
  return ok ? "action" : "error";
14856
16032
  }
14857
16033
  function resolvedinnerstep(step, plan) {
14858
- const options = stepoptions3(step);
16034
+ const options = stepoptions6(step);
14859
16035
  if (typeof options.stepid === "string" && options.stepid.trim()) {
14860
16036
  return plan.steps.find((candidate) => candidate.id === options.stepid) ?? null;
14861
16037
  }
@@ -14864,7 +16040,7 @@ function resolvedinnerstep(step, plan) {
14864
16040
  async function executekeyhold(step, session, plan, tabid2, origin) {
14865
16041
  const output = await dispatchpagestep(step, tabid2, origin, plan);
14866
16042
  if (!output?.ok) return output ?? { ok: false, summary: "The key hold was not delivered." };
14867
- const options = stepoptions3(step);
16043
+ const options = stepoptions6(step);
14868
16044
  const holdid = typeof options.holdid === "string" && options.holdid.trim() ? options.holdid : randomid();
14869
16045
  const modifiers = Array.isArray(options.modifiers) ? options.modifiers.filter((item) => typeof item === "string") : [];
14870
16046
  const hold = { holdid, key: step.value ?? "", ...modifiers.length > 0 ? { modifiers } : {}, tabid: tabid2, stepid: step.id, pressedat: Date.now() };
@@ -14897,7 +16073,7 @@ async function executedismissdialog(step, session, plan, tabid2, origin) {
14897
16073
  return { ok: true, summary: `Dialog handler armed${answer} for the next confirm, alert or prompt.` };
14898
16074
  }
14899
16075
  async function executeretryaction(step, session, plan, tabid2, origin) {
14900
- const rule = stepoptions3(step).retryrule;
16076
+ const rule = stepoptions6(step).retryrule;
14901
16077
  const inner = resolvedinnerstep(step, plan);
14902
16078
  if (!inner) throw new Error("The reviewed wrapper step could not be resolved.");
14903
16079
  const innergate = validatestep(inner, origin);
@@ -14933,8 +16109,8 @@ async function executeenterframe(step, plan, tabid2, origin) {
14933
16109
  if (!inner) throw new Error("The reviewed frame wrapper step could not be resolved.");
14934
16110
  const innergate = validatestep(inner, origin);
14935
16111
  if (!innergate.allowed) throw new Error(`The wrapped step is not allowed: ${innergate.reason}`);
14936
- const options = stepoptions3(step);
14937
- const inneroptions = inner.options ? stepoptions3(inner) : void 0;
16112
+ const options = stepoptions6(step);
16113
+ const inneroptions = inner.options ? stepoptions6(inner) : void 0;
14938
16114
  const derived = { ...step, options: JSON.stringify({ ...options, kind: inner.kind, ...inner.target ? { target: inner.target } : {}, ...inner.value ? { value: inner.value } : {}, ...inneroptions ? { options: inneroptions } : {} }) };
14939
16115
  return dispatchpagestep(derived, tabid2, origin, plan);
14940
16116
  }
@@ -14946,7 +16122,7 @@ function detailarray(details, key) {
14946
16122
  return Array.isArray(value) ? value : [];
14947
16123
  }
14948
16124
  async function executediffsnapshots(step, session, plan, tabid2, origin) {
14949
- const options = stepoptions3(step);
16125
+ const options = stepoptions6(step);
14950
16126
  const versions = Array.isArray(options.versions) ? options.versions.filter((item) => typeof item === "number") : [];
14951
16127
  const baseversion = versions[0];
14952
16128
  const targetversion = versions[1];
@@ -14969,7 +16145,7 @@ async function executediffsnapshots(step, session, plan, tabid2, origin) {
14969
16145
  return { ok: Boolean(output.ok), summary: output.summary, details: { ...output.details ?? {}, versions: [baseversion, targetversion] } };
14970
16146
  }
14971
16147
  async function executewatchstep(step, session, plan, tabid2, origin) {
14972
- const options = stepoptions3(step);
16148
+ const options = stepoptions6(step);
14973
16149
  const watchid = typeof options.watchid === "string" && options.watchid.trim() ? options.watchid : randomid();
14974
16150
  const scopes = Array.isArray(options.scopes) ? options.scopes.filter((item) => typeof item === "string" && item.trim().length > 0) : [];
14975
16151
  const events = Array.isArray(options.events) ? options.events.filter((item) => typeof item === "string" && item.trim().length > 0) : [];
@@ -15651,7 +16827,7 @@ function commandtabids(step, options) {
15651
16827
  return listed.length > 0 ? listed : single;
15652
16828
  }
15653
16829
  async function executetabscommand(step, session, plan, sessiontabid) {
15654
- const options = stepoptions3(step);
16830
+ const options = stepoptions6(step);
15655
16831
  const extra = { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id };
15656
16832
  const windowid = step.value && /^\d+$/.test(step.value) ? Number.parseInt(step.value, 10) : 0;
15657
16833
  const layoutgate = layoutmutationgranted(session, Date.now());
@@ -15927,7 +17103,7 @@ async function executetabscommand(step, session, plan, sessiontabid) {
15927
17103
  }
15928
17104
  }
15929
17105
  async function executesaveprofiles(step, session, origin) {
15930
- const options = stepoptions3(step);
17106
+ const options = stepoptions6(step);
15931
17107
  const record2 = parseformrecord(options.formrecord);
15932
17108
  const name = typeof options.name === "string" ? options.name : "";
15933
17109
  if (!name || !record2) throw new Error("A reviewed profile name and form record are required.");
@@ -15947,7 +17123,7 @@ async function executeasksubmit(step, session, plan, tabid2, origin) {
15947
17123
  return { ok: true, summary: `Asksubmit prompt opened for form ${ticket.form || "the reviewed form"}; the submission waits for your approval.`, details: { ticket, values } };
15948
17124
  }
15949
17125
  async function executesubmitform(step, session, plan, tabid2, origin) {
15950
- const consentref = typeof stepoptions3(step).consentref === "string" ? stepoptions3(step).consentref : "";
17126
+ const consentref = typeof stepoptions6(step).consentref === "string" ? stepoptions6(step).consentref : "";
15951
17127
  const ticket = (await memory.gettickets()).find((item) => item.approved === true && (item.consentref === consentref || item.id === consentref));
15952
17128
  if (!ticket) throw new Error("No approved asksubmit ticket matches the reviewed consent ref; approve the submission in the review panel first.");
15953
17129
  const output = await dispatchpagestep(step, tabid2, origin, plan) ?? { ok: false, summary: "The form submission returned no result." };
@@ -15971,7 +17147,7 @@ async function executeretryform(step, session, plan, tabid2, origin) {
15971
17147
  return { ok: Boolean(output?.ok), summary: output?.summary ?? "The retried submission returned no result.", details: { attempts, windows, ok: Boolean(output?.ok) } };
15972
17148
  }
15973
17149
  async function executeconsentpassword(step, session, plan, tabid2, origin) {
15974
- const consentref = typeof stepoptions3(step).consentref === "string" ? stepoptions3(step).consentref : "";
17150
+ const consentref = typeof stepoptions6(step).consentref === "string" ? stepoptions6(step).consentref : "";
15975
17151
  const gate = passwordconsentgranted(step);
15976
17152
  if (!gate.allowed) throw new Error(gate.reason ?? "A password fill requires a reviewed consent ref.");
15977
17153
  const output = await dispatchpagestep(step, tabid2, origin, plan);
@@ -15983,7 +17159,7 @@ async function executeattachfile(step, session, plan, tabid2, origin) {
15983
17159
  const artifacts = await memory.getartifacts();
15984
17160
  const artifact = artifacts.find((item) => item.name === name || item.id === name);
15985
17161
  if (!artifact) throw new Error(`No generated artifact named ${name} exists in the run store yet.`);
15986
- const derived = { ...step, options: JSON.stringify({ ...stepoptions3(step), artifact: artifact.id, artifactname: artifact.name }) };
17162
+ const derived = { ...step, options: JSON.stringify({ ...stepoptions6(step), artifact: artifact.id, artifactname: artifact.name }) };
15987
17163
  const output = await dispatchpagestep(derived, tabid2, origin, plan);
15988
17164
  await audit("fill", `Artifact ${artifact.name} of kind ${artifact.kind} attached to the reviewed file input inside the form submission.`, { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id });
15989
17165
  return { ...output ?? { ok: false, summary: "The artifact attachment returned no result." }, details: { ...output?.details ?? {}, artifact } };
@@ -16016,7 +17192,7 @@ async function executeformstep(step, session, plan, tabid2, origin) {
16016
17192
  return executecaptchahandoff(step, session, plan, tabid2, origin);
16017
17193
  case "fillcode": {
16018
17194
  const stored = await memory.getcodevalue();
16019
- const source = typeof stepoptions3(step).source === "string" ? stepoptions3(step).source : "";
17195
+ const source = typeof stepoptions6(step).source === "string" ? stepoptions6(step).source : "";
16020
17196
  const derived = stored !== void 0 && source === "reviewed" ? { ...step, value: stored } : step;
16021
17197
  const output = await dispatchpagestep(derived, tabid2, origin, plan);
16022
17198
  await audit("fill", `One time code typed from the reviewed source ${source}${stored !== void 0 ? " through the consent gated code entry" : ""}.`, { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id });
@@ -16087,7 +17263,7 @@ async function storeexport(stepid, datasetvalue, format, delimiter, session, pla
16087
17263
  return artifact;
16088
17264
  }
16089
17265
  async function executedatastep(step, session, plan, tabid2, origin) {
16090
- const options = stepoptions3(step);
17266
+ const options = stepoptions6(step);
16091
17267
  const extra = { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id };
16092
17268
  switch (step.kind) {
16093
17269
  case "scrapetable": {
@@ -16317,7 +17493,7 @@ async function verifyonerecord(record2, expected, extra) {
16317
17493
  return { ok: verification.ok, summary: verification.summary, details: { verification: { ...verification.matches, state: record2.state, path: record2.path, checksum: record2.checksum, bytes: record2.bytes } } };
16318
17494
  }
16319
17495
  async function executefilesstep(step, session, plan, tabid2, origin) {
16320
- const options = stepoptions3(step);
17496
+ const options = stepoptions6(step);
16321
17497
  const extra = { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id };
16322
17498
  switch (step.kind) {
16323
17499
  case "batchdownload": {
@@ -16546,7 +17722,7 @@ reconcilmimefilter().catch(() => {
16546
17722
  });
16547
17723
  var stitchprogress = /* @__PURE__ */ new Map();
16548
17724
  function stepcaptureoptions(step) {
16549
- return captureoptionsof(stepoptions3(step).capture);
17725
+ return captureoptionsof(stepoptions6(step).capture);
16550
17726
  }
16551
17727
  async function blobtodataurl(blob) {
16552
17728
  const buffer = new Uint8Array(await blob.arrayBuffer());
@@ -16670,7 +17846,7 @@ async function encodecanvas(width, height, draw, options) {
16670
17846
  return canvasdataurl(canvas, options.format, options.quality);
16671
17847
  }
16672
17848
  async function capturenamefor(step, plan, kind, format) {
16673
- const naming = stepoptions3(step).naming;
17849
+ const naming = stepoptions6(step).naming;
16674
17850
  const rule = naming && typeof naming === "object" && !Array.isArray(naming) ? naming : { run: true, step: true, sequence: true, kind: true };
16675
17851
  const counters = (await memory.getcapturecounters()).find((item) => item.taskid === plan.id);
16676
17852
  const advanced = advancecounter(counters?.counters ?? {}, step.id);
@@ -16710,13 +17886,62 @@ async function grabstateshot(step, session, plan, tabid2, phase) {
16710
17886
  return record2;
16711
17887
  }
16712
17888
  async function storecapture(record2, session, plan, step, origin) {
17889
+ const template = templateof(step);
17890
+ const regions = regionsfor(await memory.getredactregions(), origin, template);
17891
+ record2 = redactedshot(record2, regions);
16713
17892
  await memory.addcapture(record2);
17893
+ if (regions.length > 0) await audit("capture", `The capture of ${origin} on the template ${template} stored with its sensitive regions masked: ${redactionsummary(regions)}`, { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id });
16714
17894
  const routed = await routecapture(record2, session, plan, step, origin);
16715
17895
  await memory.setprogress(recordcapture(await memory.getprogress(), plan.id, step.id, record2, Date.now()));
16716
17896
  await refreshbadge();
16717
17897
  return { record: record2, routed };
16718
17898
  }
17899
+ var activeredactregions = [];
17900
+ async function drawredactoverlays(tabid2) {
17901
+ if (activeredactregions.length === 0) return;
17902
+ const rects = activeredactregions.map((region) => ({ x: region.x, y: region.y, width: region.width, height: region.height }));
17903
+ await chrome.scripting.executeScript({ target: { tabId: tabid2 }, func: (overlays) => {
17904
+ let host = document.getElementById("devthinkredacthost");
17905
+ if (!host) {
17906
+ host = document.createElement("div");
17907
+ host.id = "devthinkredacthost";
17908
+ host.style.position = "fixed";
17909
+ host.style.inset = "0";
17910
+ host.style.zIndex = "2147483647";
17911
+ host.style.pointerEvents = "none";
17912
+ document.documentElement.appendChild(host);
17913
+ }
17914
+ for (const overlay of overlays) {
17915
+ const rect = document.createElement("div");
17916
+ rect.style.position = "fixed";
17917
+ rect.style.left = `${overlay.x}px`;
17918
+ rect.style.top = `${overlay.y}px`;
17919
+ rect.style.width = `${overlay.width}px`;
17920
+ rect.style.height = `${overlay.height}px`;
17921
+ rect.style.background = "#000";
17922
+ host.appendChild(rect);
17923
+ }
17924
+ }, args: [rects] }).catch(() => {
17925
+ });
17926
+ }
17927
+ async function clearredactoverlays(tabid2) {
17928
+ if (activeredactregions.length === 0) return;
17929
+ await chrome.scripting.executeScript({ target: { tabId: tabid2 }, func: () => {
17930
+ document.getElementById("devthinkredacthost")?.remove();
17931
+ } }).catch(() => {
17932
+ });
17933
+ }
16719
17934
  async function executecapturestep(step, session, plan, tabid2, origin) {
17935
+ activeredactregions = regionsfor(await memory.getredactregions(), origin, templateof(step));
17936
+ await drawredactoverlays(tabid2);
17937
+ try {
17938
+ return await executecapturestepinner(step, session, plan, tabid2, origin);
17939
+ } finally {
17940
+ await clearredactoverlays(tabid2);
17941
+ activeredactregions = [];
17942
+ }
17943
+ }
17944
+ async function executecapturestepinner(step, session, plan, tabid2, origin) {
16720
17945
  const options = stepcaptureoptions(step);
16721
17946
  const format = options.format ?? "png";
16722
17947
  const ratio = options.pixelratio ?? 1;
@@ -16739,7 +17964,7 @@ async function executecapturestep(step, session, plan, tabid2, origin) {
16739
17964
  return { ok: true, summary: `Captured the visible viewport at ${record2.width} by ${record2.height} pixels.`, details: { capture: { id: record2.id, kind: record2.kind, format: record2.format, width: record2.width, height: record2.height, bytes: (record2.bytes ?? "").length, exporttarget: stored.routed.target } } };
16740
17965
  }
16741
17966
  if (step.kind === "shotfullpage") {
16742
- const rawoptions = stepoptions3(step);
17967
+ const rawoptions = stepoptions6(step);
16743
17968
  const settle2 = typeof rawoptions.settle === "number" ? rawoptions.settle : 150;
16744
17969
  const overlap = typeof rawoptions.overlap === "number" ? rawoptions.overlap : 0;
16745
17970
  const wait = typeof rawoptions.wait === "number" ? rawoptions.wait : void 0;
@@ -16776,7 +18001,7 @@ async function executecapturestep(step, session, plan, tabid2, origin) {
16776
18001
  }
16777
18002
  if (step.kind === "shotelement") {
16778
18003
  const selector = step.target ?? "";
16779
- const settle2 = typeof stepoptions3(step).settle === "number" ? stepoptions3(step).settle : 150;
18004
+ const settle2 = typeof stepoptions6(step).settle === "number" ? stepoptions6(step).settle : 150;
16780
18005
  const measured = await bridgecall(tabid2, "measurepage");
16781
18006
  const targetinfo = await bridgecall(tabid2, "elementrect", selector);
16782
18007
  if (!targetinfo.ok || !targetinfo.rect) throw new Error(targetinfo.summary);
@@ -16817,7 +18042,7 @@ async function executecapturestep(step, session, plan, tabid2, origin) {
16817
18042
  }
16818
18043
  }
16819
18044
  if (step.kind === "shotregion") {
16820
- const rawoptions = stepoptions3(step);
18045
+ const rawoptions = stepoptions6(step);
16821
18046
  const rect = rawoptions.regionrect;
16822
18047
  if (!rect) throw new Error("A reviewed regionrect is required in options.");
16823
18048
  const container = typeof rawoptions.container === "string" ? rawoptions.container : void 0;
@@ -16858,7 +18083,7 @@ async function executecapturestep(step, session, plan, tabid2, origin) {
16858
18083
  }
16859
18084
  }
16860
18085
  if (step.kind === "contactsheet") {
16861
- const rawoptions = stepoptions3(step);
18086
+ const rawoptions = stepoptions6(step);
16862
18087
  const elements = (Array.isArray(rawoptions.elements) ? rawoptions.elements : []).filter((item) => typeof item === "string" && item.trim().length > 0);
16863
18088
  const layout = rawoptions.sheet && typeof rawoptions.sheet === "object" && !Array.isArray(rawoptions.sheet) ? rawoptions.sheet : { cellsize: 240, columns: 3, label: "both" };
16864
18089
  const measured = await bridgecall(tabid2, "measurepage");
@@ -16969,7 +18194,7 @@ async function thumbonecapture(source, directive, plan, step) {
16969
18194
  return { id: randomid(), runid: plan.id, stepid: step.id, kind: "makethumbs", format, width: geometry.width, height: geometry.height, capturedat: Date.now(), bytes: dataurl, name, target: source.id };
16970
18195
  }
16971
18196
  async function executemediastep(step, session, plan, tabid2, origin) {
16972
- const options = stepoptions3(step);
18197
+ const options = stepoptions6(step);
16973
18198
  const extra = { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id };
16974
18199
  const gate = mediagate(session, tabid2, origin, Date.now());
16975
18200
  if (!gate.allowed) throw new Error(gate.reason ?? "The media capture needs the active session tab grant.");
@@ -17228,7 +18453,7 @@ async function attachapikeys(names, origin) {
17228
18453
  return { headers, keys: attached };
17229
18454
  }
17230
18455
  async function executehttpstep(step, session, plan, tabid2, origin) {
17231
- const options = stepoptions3(step);
18456
+ const options = stepoptions6(step);
17232
18457
  const extra = { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id };
17233
18458
  if (step.kind === "fetchurl") {
17234
18459
  const request = fetchrequestof(options.fetch);
@@ -17493,7 +18718,7 @@ async function closechannelsforrun(runid) {
17493
18718
  channelbuses.clear();
17494
18719
  }
17495
18720
  async function executesocketstep(step, session, plan, tabid2, origin) {
17496
- const options = stepoptions3(step);
18721
+ const options = stepoptions6(step);
17497
18722
  const extra = { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id };
17498
18723
  if (step.kind === "opensocket") {
17499
18724
  const channel = channeloptionsof(options.socket);
@@ -17627,7 +18852,7 @@ async function executesocketstep(step, session, plan, tabid2, origin) {
17627
18852
  throw new Error("Unsupported socket observation kind.");
17628
18853
  }
17629
18854
  async function executenetwatchstep(step, session, plan, tabid2, origin) {
17630
- const options = stepoptions3(step);
18855
+ const options = stepoptions6(step);
17631
18856
  const extra = { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id };
17632
18857
  if (step.kind === "watchrequests") {
17633
18858
  const watch = options.watch && typeof options.watch === "object" && !Array.isArray(options.watch) ? options.watch : {};
@@ -17779,7 +19004,7 @@ function timelinedetail(entry, runid) {
17779
19004
  return { id: randomid(), runid, stepid: record2.stepid, time: record2.time, level: record2.level, source: record2.source, message: record2.message };
17780
19005
  }
17781
19006
  async function executetimelinestep(step, session, plan, tabid2, origin) {
17782
- const options = stepoptions3(step);
19007
+ const options = stepoptions6(step);
17783
19008
  const watch = options.watch && typeof options.watch === "object" && !Array.isArray(options.watch) ? options.watch : {};
17784
19009
  const watchwindow = typeof watch.window === "number" && Number.isFinite(watch.window) && watch.window >= 0 ? watch.window : 0;
17785
19010
  const extra = { sessionid: session.id, planid: plan.id, stepid: step.id };
@@ -17934,7 +19159,7 @@ function pauseframes(entry) {
17934
19159
  });
17935
19160
  }
17936
19161
  async function executecdpstep(step, session, plan, tabid2, origin) {
17937
- const options = stepoptions3(step);
19162
+ const options = stepoptions6(step);
17938
19163
  const extra = { sessionid: session.id, planid: plan.id, stepid: step.id };
17939
19164
  const debuggatecheck = debuggate(session, tabid2, origin, Date.now());
17940
19165
  if (!debuggatecheck.allowed) throw new Error(debuggatecheck.reason ?? "The devtools protocol step stays outside the debug gate.");
@@ -18168,7 +19393,7 @@ async function sampleheapforstep(tracker, stepid, tabid2, origin, plan) {
18168
19393
  if (trend.flaggedsteps.includes(stepid)) await memory.addtimelineentry({ id: randomid(), runid: tracker.runid, stepid, time: now, level: "warn", source: "longtask", message: `Heap growth of step ${stepid} exceeds the reviewed slope of ${tracker.slope} bytes per millisecond; the step is flagged in the memory trend.` });
18169
19394
  }
18170
19395
  async function executeprofilestep(step, session, plan, tabid2, origin) {
18171
- const options = stepoptions3(step);
19396
+ const options = stepoptions6(step);
18172
19397
  const extra = { sessionid: session.id, planid: plan.id, stepid: step.id };
18173
19398
  const targets = profiletargetsof(options);
18174
19399
  const grants = await memory.getdebuggergrants();
@@ -18497,7 +19722,7 @@ async function controlledfetch(runid, url, init, controller, window2, streamstat
18497
19722
  return response;
18498
19723
  }
18499
19724
  async function executenetcontrolstep(step, session, plan, tabid2, origin) {
18500
- const options = stepoptions3(step);
19725
+ const options = stepoptions6(step);
18501
19726
  const extra = { ...session ? { sessionid: session.id } : {}, planid: plan.id, stepid: step.id };
18502
19727
  const ruleset = rulesetof(plan.id);
18503
19728
  if (step.kind === "blockrequest") {
@@ -18744,7 +19969,7 @@ async function enforcewindowreview(step, session, plan) {
18744
19969
  const progress = plan ? await memory.getprogress() : void 0;
18745
19970
  const tasktabids = plan ? trackedtasktabs(progress, plan.id) : [];
18746
19971
  const count = tasktabsinwindow(await livetabs(), windowid, tasktabids);
18747
- const gate = windowclosegate(count, stepoptions3(step).reviewed === true);
19972
+ const gate = windowclosegate(count, stepoptions6(step).reviewed === true);
18748
19973
  if (!gate.allowed) throw new Error(gate.reason ?? "The window close needs explicit review.");
18749
19974
  if (session && count > 0) await audit("window", `Window ${windowid} closes while holding ${count} task tab${count === 1 ? "" : "s"} under the explicit reviewed flag.`, { ...session ? { sessionid: session.id } : {}, ...plan ? { planid: plan.id } : {}, stepid: step.id });
18750
19975
  }
@@ -18830,7 +20055,7 @@ async function revertemulationforrun(runid, reason, tabid2) {
18830
20055
  }
18831
20056
  }
18832
20057
  async function executeemulationstep(step, session, plan, tabid2, origin) {
18833
- const options = stepoptions3(step);
20058
+ const options = stepoptions6(step);
18834
20059
  const extra = { sessionid: session.id, planid: plan.id, stepid: step.id };
18835
20060
  const revertplan = revertplanof(options.revertplan) ?? [];
18836
20061
  const family = familyofkind(step.kind) ?? "device";
@@ -18962,7 +20187,7 @@ async function performrestore(record2, restore, session) {
18962
20187
  return { restored, skippedorigins: grantscheck.skippedorigins };
18963
20188
  }
18964
20189
  async function executesessionstep(step, session, plan, tabid2, origin) {
18965
- const options = stepoptions3(step);
20190
+ const options = stepoptions6(step);
18966
20191
  const extra = { sessionid: session.id, planid: plan.id, stepid: step.id };
18967
20192
  if (step.kind === "persiststate") {
18968
20193
  const progress = await memory.getprogress();
@@ -19107,7 +20332,7 @@ async function dispatchworkflowstep(step, context) {
19107
20332
  return { ok: Boolean(output.ok), summary: output.summary, ...output.details !== void 0 ? { details: output.details } : {} };
19108
20333
  }
19109
20334
  async function executedelaystep(step) {
19110
- const options = stepoptions3({ id: step.id, kind: step.kind, summary: step.label, risk: "read", ...step.options !== void 0 ? { options: step.options } : {} });
20335
+ const options = stepoptions6({ id: step.id, kind: step.kind, summary: step.label, risk: "read", ...step.options !== void 0 ? { options: step.options } : {} });
19111
20336
  const delay = delayof(options.delay);
19112
20337
  const sampled = delayjitter(delay, hashseed(`${step.id}:${Date.now()}`));
19113
20338
  const transport = await sleepreviewed(sampled, step.id);
@@ -19154,7 +20379,7 @@ async function sleepreviewed(sampled, stepid) {
19154
20379
  return "timer";
19155
20380
  }
19156
20381
  async function executewaitelement(step, tabid2) {
19157
- const options = stepoptions3({ id: step.id, kind: step.kind, summary: step.label, risk: "read", ...step.target !== void 0 ? { target: step.target } : {}, ...step.options !== void 0 ? { options: step.options } : {} });
20382
+ const options = stepoptions6({ id: step.id, kind: step.kind, summary: step.label, risk: "read", ...step.target !== void 0 ? { target: step.target } : {}, ...step.options !== void 0 ? { options: step.options } : {} });
19158
20383
  const wait = waitof(options.wait, step.target);
19159
20384
  const startedat = Date.now();
19160
20385
  const starttab = await chrome.tabs.get(tabid2).catch(() => void 0);
@@ -19182,7 +20407,7 @@ function waitof(value, target) {
19182
20407
  return { selector, timeout, poll };
19183
20408
  }
19184
20409
  async function executecomputestep(step, session) {
19185
- const options = stepoptions3({ id: step.id, kind: step.kind, summary: step.label, risk: "read", ...step.options !== void 0 ? { options: step.options } : {} });
20410
+ const options = stepoptions6({ id: step.id, kind: step.kind, summary: step.label, risk: "read", ...step.options !== void 0 ? { options: step.options } : {} });
19186
20411
  const expression = options.expression;
19187
20412
  if (!expression || typeof expression !== "object") throw new Error("The compute step needs a reviewed expression.");
19188
20413
  const scopes = runscopes(options.variables);
@@ -19191,7 +20416,7 @@ async function executecomputestep(step, session) {
19191
20416
  return { ok: true, summary: `Computed ${expression.result} = ${typeof value === "string" ? `"${value}"` : String(value)} through the ${expression.operator} operator.`, details: { result: expression.result, kind: expression.resultkind, value } };
19192
20417
  }
19193
20418
  async function executeextractvarsstep(step, session) {
19194
- const options = stepoptions3({ id: step.id, kind: step.kind, summary: step.label, risk: "read", ...step.value !== void 0 ? { value: step.value } : {}, ...step.options !== void 0 ? { options: step.options } : {} });
20419
+ const options = stepoptions6({ id: step.id, kind: step.kind, summary: step.label, risk: "read", ...step.value !== void 0 ? { value: step.value } : {}, ...step.options !== void 0 ? { options: step.options } : {} });
19195
20420
  const rule = options.rule;
19196
20421
  if (!rule || typeof rule !== "object" || typeof rule.pattern !== "string") throw new Error("The variable extraction needs a reviewed regex rule.");
19197
20422
  const text2 = typeof options.text === "string" ? options.text : step.value ?? "";
@@ -19204,7 +20429,7 @@ async function executeextractvarsstep(step, session) {
19204
20429
  return { ok: true, summary: `Captured ${extraction.variables.length} variable${extraction.variables.length === 1 ? "" : "s"} from the reviewed text.`, details: { matched: true, variables: extraction.variables } };
19205
20430
  }
19206
20431
  async function executeworkflowstep(step, session, plan, tabid2, origin) {
19207
- const options = stepoptions3(step);
20432
+ const options = stepoptions6(step);
19208
20433
  if (step.kind === "composeworkflow") {
19209
20434
  const payload = options.workflow;
19210
20435
  if (!payload || typeof payload !== "object" || Array.isArray(payload)) throw new Error("The workflow composition needs the reviewed workflow payload.");
@@ -19260,7 +20485,7 @@ function workflowstepofentry(value) {
19260
20485
  return blockinvocationof(value);
19261
20486
  }
19262
20487
  async function executeworkflowrun(step, session, plan, tabid2, origin, dry) {
19263
- const options = stepoptions3(step);
20488
+ const options = stepoptions6(step);
19264
20489
  const workflowid = typeof options.workflowid === "string" ? options.workflowid : "";
19265
20490
  const storedrecord = await memory.getworkflowrecord(workflowid);
19266
20491
  if (!storedrecord) throw new Error(`No composed workflow matches ${workflowid || "the reviewed id"}.`);
@@ -19423,7 +20648,7 @@ async function storetimeoutabort(run, step, message, budget) {
19423
20648
  return { run: aborted, log: [entry] };
19424
20649
  }
19425
20650
  async function executetriggerstep(step, session, plan, tabid2, origin) {
19426
- const options = stepoptions3(step);
20651
+ const options = stepoptions6(step);
19427
20652
  const family = triggerfamilyof(step.kind);
19428
20653
  if (!family) throw new Error(`The ${step.kind} step is not a reviewed trigger kind.`);
19429
20654
  const workflowid = typeof options.workflowid === "string" ? options.workflowid : "";
@@ -19643,12 +20868,15 @@ async function executeaction(step, session, plan, tabid2, origin, settings, verd
19643
20868
  }
19644
20869
  await audit("deny", `The ${step.kind} step ${step.id} on ${origin} was denied without navigation: ${securityverdict.reason}`, { ...session ? { sessionid: session.id } : {}, ...plan ? { planid: plan.id } : {}, stepid: step.id });
19645
20870
  if (securityverdict.suspended && session) {
20871
+ await memory.addconsentmemoryentry(consentmemoryof({ origin, decision: "expire", boundary: "the consent window boundary that expired mid step", kinds: [step.kind], now: Date.now() })).catch(() => {
20872
+ });
19646
20873
  await appendrunevent("expiry", `The consent window of ${origin} expired mid step and the run suspended at the step ${step.id}; a new explicit prompt renews it.`, session, origin, step.id).catch(() => {
19647
20874
  });
19648
20875
  await audit("expiry", `The consent window of ${origin} expired mid step and the run suspended at the step ${step.id}; the executor refuses to resume without a new explicit prompt.`, { sessionid: session.id, ...plan ? { planid: plan.id } : {}, stepid: step.id });
19649
20876
  }
19650
20877
  throw new Error(securityverdict.reason);
19651
20878
  }
20879
+ step = await resolvevaultvalues(step, session);
19652
20880
  if (session && plan && plan.state === "approved" && mode === "plan") await openplanrun(session, plan);
19653
20881
  if (plan && plan.state === "approved") await markpendingstep(plan, step.id);
19654
20882
  if (routing.environment === "sandboxframe") return executesandboxrender(step, session, plan, origin);
@@ -19781,6 +21009,17 @@ async function executeaction(step, session, plan, tabid2, origin, settings, verd
19781
21009
  const auditkind = stepauditkind(step, Boolean(output?.ok));
19782
21010
  await audit(auditkind, summary, { ...session ? { sessionid: session.id } : {}, ...plan ? { planid: plan.id } : {}, stepid: step.id });
19783
21011
  await memory.addoutcome(outcome);
21012
+ if (session && plan) await memory.appendscratchentry(scratchentryof({ taskid: plan.id, sessionid: session.id, text: `${step.kind} ${step.id} ${outcome.ok ? "completed" : "failed"}: ${summary}`, stepid: step.id, author: "agent", now: Date.now() })).catch(() => {
21013
+ });
21014
+ if (plan) await memory.addrecallentry(recallentryof({ origin, runid: plan.id, stepid: step.id, text: summary, at: Date.now() })).catch(() => {
21015
+ });
21016
+ let stepretry;
21017
+ if (!outcome.ok && plan) {
21018
+ const surface = errorsurfaceof({ stepid: step.id, runid: plan.id, message: summary, cause: classifyfailure({ message: summary, policyrefused: false, gatewait: false }), retryallowed: true, retryreason: "The failed step may dispatch again through the full consent gate chain.", context: { origin, kind: step.kind, environment: routing.environment }, now: Date.now() });
21019
+ await memory.adderrorsurface(surface).catch(() => {
21020
+ });
21021
+ stepretry = { allowed: true, reason: `The ${surface.cause} failure of the step ${step.id} may retry through a new reviewed dispatch; the retry rides the full consent gate chain and never bypasses the review.` };
21022
+ }
19784
21023
  if (session) await appendrunevent("step", `The ${step.kind} step ${step.id} ${outcome.ok ? "completed" : "failed"} on ${origin}: ${summary}${securityverdict.classification.sensitive ? ` The step grades ${securityverdict.classification.reason}` : ""}`, session, origin, step.id).catch(() => {
19785
21024
  });
19786
21025
  if (output?.ok && plan && mode === "plan") {
@@ -19812,11 +21051,36 @@ async function executeaction(step, session, plan, tabid2, origin, settings, verd
19812
21051
  const done = { ...plan, state: "completed", completedat: Date.now() };
19813
21052
  await memory.setplan(done);
19814
21053
  await closeplanrun(done.id, session?.id ?? "");
21054
+ await distillcompletedrun(done, tracked, session, settings).catch(() => {
21055
+ });
19815
21056
  await audit("complete", "Every reviewed step of the approved plan has executed.", { ...session ? { sessionid: session.id } : {}, planid: done.id });
19816
21057
  }
19817
21058
  }
21059
+ if (stepretry !== void 0 && output !== void 0) return { ...output, retry: stepretry };
21060
+ if (stepretry !== void 0) return { ok: false, summary, retry: stepretry };
19818
21061
  return output ?? { ok: false, summary };
19819
21062
  }
21063
+ async function distillcompletedrun(plan, progress, session, settings) {
21064
+ const log = await memory.getimmutablelog(plan.id);
21065
+ const origins = [.../* @__PURE__ */ new Set([session?.origin ?? "", ...(log?.entries ?? []).map((entry) => entry.origin).filter((entryorigin) => entryorigin !== "")])].filter((entryorigin) => entryorigin !== "");
21066
+ let provenance = "inline";
21067
+ const inline = distillrunsummary({ plan, outcomes: progress.outcomes ?? [], origins, sessionid: session?.id ?? "", ...settings?.summarywindow !== void 0 ? { window: settings.summarywindow } : {}, provenance: "inline", now: Date.now() });
21068
+ const ready = await ensureoffscreendocument(plan.id).catch(() => false);
21069
+ if (ready) {
21070
+ const request = summaryrequestof({ id: randomid(), runid: plan.id, sessionid: session?.id ?? "", payload: JSON.stringify({ runid: plan.id, steps: inline.steps.length, window: settings?.summarywindow }), sentat: Date.now() });
21071
+ try {
21072
+ const answer = await chrome.runtime.sendMessage({ kind: "offscreen", action: "summary", request: { id: request.id, runid: request.runid, stepid: request.stepid, task: runsummarytask, payload: request.payload, transferables: [] } });
21073
+ if (answer && answer.ok !== false) provenance = "offscreenworker";
21074
+ } catch {
21075
+ }
21076
+ }
21077
+ const summary = { ...inline, provenance };
21078
+ await memory.setrunsummary(summary);
21079
+ await memory.trackrunsummary(plan.id);
21080
+ if (settings?.historyindex !== false) await memory.addhistoryentry(summaryhistoryentry(summary));
21081
+ await audit("summary", `The run summary of ${plan.id} distilled ${summary.steps.length} step outcome${summary.steps.length === 1 ? "" : "s"} across ${summary.origins.length} origin${summary.origins.length === 1 ? "" : "s"} as one ${provenance === "offscreenworker" ? "offscreen worker task" : "inline distillation"}${summary.window !== void 0 ? ` inside the user configured window of ${summary.window} steps` : " with no window cap"}.`, { ...session ? { sessionid: session.id } : {}, planid: plan.id });
21082
+ return summary;
21083
+ }
19820
21084
  async function previewstep(stepid) {
19821
21085
  const session = await memory.getsession();
19822
21086
  const plan = await memory.getplan();
@@ -19825,7 +21089,7 @@ async function previewstep(stepid) {
19825
21089
  if (!step) throw new Error("Reviewed step was not found.");
19826
21090
  const gate = canpreview({ session, plan, step, tabid: tab.id, origin });
19827
21091
  if (!gate.allowed) throw new Error(gate.reason);
19828
- if (!step.target && !stepoptions3(step).targetref) throw new Error("Only a target-based step can be previewed.");
21092
+ if (!step.target && !stepoptions6(step).targetref) throw new Error("Only a target-based step can be previewed.");
19829
21093
  const result = await chrome.scripting.executeScript({ target: { tabId: tab.id }, func: (action, expectedorigin) => {
19830
21094
  const bridge = globalThis.devthinkbridge;
19831
21095
  if (!bridge) throw new Error("Devthink page bridge is unavailable.");
@@ -19876,8 +21140,253 @@ async function extractionreportValue() {
19876
21140
  async function provenancereportValue() {
19877
21141
  return provenancereport({ records: await memory.getprovenances() });
19878
21142
  }
21143
+ var commandschemas = {
21144
+ security: { allowlist: "object", profile: "object", consent: "object", revoke: "object", mask: "object", read: "object", export: "object", settings: "object", gate: "object", vault: "object", connectallow: "object", ratelimit: "object", redact: "object" },
21145
+ sessions: { note: "object", scratch: "object", summary: "object", recall: "object", correction: "object", consent: "object", grid: "object", search: "object", cancel: "object", retry: "object", error: "object", settings: "object", bundle: "object" },
21146
+ environments: { action: "string", grants: "array", requestcapability: "boolean", pool: "object", offscreenclose: "boolean", sandbox: "object", settings: "object", render: "object", sandboxhost: "object" },
21147
+ transparency: {},
21148
+ execute: { stepid: "string" },
21149
+ configure: { endpoint: "string" }
21150
+ };
21151
+ function schemavalidation(message) {
21152
+ if (!Boolean(message) || typeof message !== "object" || Array.isArray(message)) return [{ path: "message", expected: "object", found: Array.isArray(message) ? "array" : typeof message, reason: "Every inbound command travels as one plain object; schemastrict refuses the carrier before dispatch." }];
21153
+ const command = message;
21154
+ if (typeof command.kind !== "string" || command.kind.trim() === "") return [{ path: "kind", expected: "string", found: typeof command.kind, reason: "Every inbound command names its kind as a non-empty string; a kindless command never dispatches." }];
21155
+ const schema = commandschemas[command.kind];
21156
+ if (schema === void 0) return [];
21157
+ return schemacheck({ command, schema }).errors;
21158
+ }
21159
+ async function sessionviewof() {
21160
+ const session = await memory.getsession();
21161
+ const plan = await memory.getplan();
21162
+ const settings = await memory.getsettings();
21163
+ const progress = await memory.getprogress();
21164
+ const notes = await memory.getsitenotes();
21165
+ const scratch = plan && session ? await memory.readscratchpad(plan.id, session.id) : [];
21166
+ const summaries = await memory.listrunsummaries();
21167
+ const corrections = await memory.getcorrections();
21168
+ const consentmemory = await memory.getconsentmemory();
21169
+ const index = await memory.getrecallindex();
21170
+ const scope = session ? [.../* @__PURE__ */ new Set([session.origin, ...session.grants ?? []])] : [];
21171
+ const recall = rankrecall(index, { text: plan?.objective ?? session?.origin ?? "" }, { origins: scope }).slice(0, 5);
21172
+ const errors = (await memory.geterrorsurfaces()).slice(0, 20);
21173
+ const rows = sessiongridrows({ ...session !== void 0 ? { session } : {}, ...plan !== void 0 ? { plan } : {}, ...progress !== void 0 ? { progress } : {}, logs: await memory.listimmutablelogs(), summaries, locks: await memory.getrunlocks(), tabsessions: await memory.listtabsessions() });
21174
+ return {
21175
+ grid: rows.map((row) => ({ sessionid: row.sessionid, runid: row.runid, origins: row.origins, state: row.state, outcome: row.outcome, steps: row.steps, completed: row.completed, lock: row.lock, ...row.tabid !== void 0 ? { tabid: row.tabid } : {}, ...row.sealhash !== void 0 ? { sealhash: row.sealhash } : {}, updatedat: row.updatedat, actions: row.actions })),
21176
+ notes: notes.map((note) => ({ id: note.id, origin: note.origin, title: note.title, body: notebodyof(note), author: note.author, sensitive: note.sensitive, updatedat: note.updatedat })),
21177
+ scratchpad: scratch.map((entry) => ({ id: entry.id, taskid: entry.taskid, text: entry.text, ...entry.stepid !== void 0 ? { stepid: entry.stepid } : {}, author: entry.author, at: entry.at })),
21178
+ summaries: summaries.map((summary) => ({ runid: summary.runid, origins: summary.origins, kinds: summary.kinds, steps: summary.steps.length, provenance: summary.provenance, distilledat: summary.distilledat })),
21179
+ corrections: corrections.slice(0, 20).map((entry) => ({ id: entry.id, origin: entry.origin, kind: entry.kind, stepid: entry.stepid, source: entry.source, reason: entry.reason, at: entry.at })),
21180
+ consentmemory: consentmemory.slice(0, 20).map((entry) => ({ id: entry.id, origin: entry.origin, decision: entry.decision, boundary: entry.boundary, kinds: entry.kinds, at: entry.at, ...entry.expiresat !== void 0 ? { expiresat: entry.expiresat } : {} })),
21181
+ recall: recall.map((match) => ({ origin: match.entry.origin, runid: match.entry.runid, stepid: match.entry.stepid, score: match.score, reason: match.reason })),
21182
+ errors: errors.map((surface) => ({ stepid: surface.stepid, runid: surface.runid, cause: surface.cause, message: surface.message, retry: surface.retry, at: surface.at })),
21183
+ emptystates: [
21184
+ { surface: "sessiongrid", message: rows.length === 0 ? "No session exists yet; start the first run by describing an objective and reviewing the plan the agent proposes." : "" },
21185
+ { surface: "historysearch", message: "No history matches yet; start with a first query such as an origin, a note title or a kind the runs executed." },
21186
+ { surface: "sitenotes", message: notes.length === 0 ? `No site note exists${session ? ` for ${session.origin}` : ""} yet; write the first note with a title and a body and the note flow keeps it per origin with its author provenance.` : "" },
21187
+ { surface: "scratchpad", message: scratch.length === 0 ? "The scratchpad holds no entry yet; the agent appends its per task notes here while the reviewed steps run, and every entry carries its step provenance." : "" }
21188
+ ].filter((state) => state.message !== ""),
21189
+ ...settings?.cancelrollback !== void 0 ? { cancelrollback: settings.cancelrollback } : {},
21190
+ historyindex: settings?.historyindex !== false
21191
+ };
21192
+ }
21193
+ async function handlesessionscommand(message) {
21194
+ const input = message;
21195
+ const now = Date.now();
21196
+ const session = await memory.getsession();
21197
+ const plan = await memory.getplan();
21198
+ const settings = await memory.getsettings();
21199
+ if (input.note !== void 0) {
21200
+ if (input.note.add !== void 0) {
21201
+ const origin = input.note.add.origin?.trim() || session?.origin || "";
21202
+ if (origin === "") throw new Error("The site note needs its origin.");
21203
+ const writegate = sitenoteswritegate({ consent: input.note.add.consent === true, origin });
21204
+ if (!writegate.allowed) throw new Error(writegate.reason);
21205
+ const note = sitenoteof({ origin, title: input.note.add.title ?? "", body: input.note.add.body ?? "", author: "user", ...input.note.add.sensitive === true ? { sensitive: true } : {}, now });
21206
+ await memory.writesitenote(note);
21207
+ if (settings?.historyindex !== false) await memory.addhistoryentry(notehistoryentry(note));
21208
+ await audit("notes", `The user wrote the site note ${note.id} for ${origin}${note.sensitive ? " with its body sealed at rest" : ""}; the note keeps its author provenance and its timestamps.`, { ...session ? { sessionid: session.id } : {} });
21209
+ return { ...await sessionviewof(), note };
21210
+ }
21211
+ if (input.note.edit !== void 0) {
21212
+ const id = input.note.edit.id?.trim() ?? "";
21213
+ const note = (await memory.getsitenotes()).find((candidate) => candidate.id === id);
21214
+ if (!note) throw new Error(`No site note ${id} exists to edit.`);
21215
+ const writegate = sitenoteswritegate({ consent: true, origin: note.origin });
21216
+ if (!writegate.allowed) throw new Error(writegate.reason);
21217
+ const edited = editnote(note, { title: input.note.edit.title ?? note.title, body: input.note.edit.body ?? notebodyof(note), author: "user", now });
21218
+ await memory.writesitenote(edited);
21219
+ if (settings?.historyindex !== false) await memory.addhistoryentry(notehistoryentry(edited));
21220
+ await audit("notes", `The user edited the site note ${edited.id} of ${edited.origin}; the edit keeps the created timestamp and names its author.`, { ...session ? { sessionid: session.id } : {} });
21221
+ return { ...await sessionviewof(), note: edited };
21222
+ }
21223
+ if (input.note.remove !== void 0) {
21224
+ const id = input.note.remove.id?.trim() ?? "";
21225
+ await memory.removesitenote(id);
21226
+ await audit("notes", `The user removed the site note ${id}.`, { ...session ? { sessionid: session.id } : {} });
21227
+ return { ...await sessionviewof(), removed: id };
21228
+ }
21229
+ if (input.note.list !== void 0) {
21230
+ const origin = input.note.list.origin?.trim() || session?.origin || "";
21231
+ if (origin === "") throw new Error("The site note read needs its origin.");
21232
+ const readgate = sitenotesreadgate({ origin, grants: session ? [.../* @__PURE__ */ new Set([session.origin, ...session.grants ?? []])] : [] });
21233
+ if (!readgate.allowed) throw new Error(readgate.reason);
21234
+ return { notes: (await memory.readsitenotes(origin)).map((note) => ({ id: note.id, origin: note.origin, title: note.title, body: notebodyof(note), author: note.author, sensitive: note.sensitive, updatedat: note.updatedat })) };
21235
+ }
21236
+ }
21237
+ if (input.scratch !== void 0) {
21238
+ if (!session || !plan) throw new Error("The scratchpad serves the running task of an active session.");
21239
+ const taskid = input.scratch.append?.taskid?.trim() || input.scratch.read?.taskid?.trim() || plan.id;
21240
+ const scopegate2 = scratchpadscopegate({ taskid, sessionid: session.id, entrytaskid: taskid, entrysessionid: session.id });
21241
+ if (!scopegate2.allowed) throw new Error(scopegate2.reason);
21242
+ if (input.scratch.append !== void 0) {
21243
+ const entry = scratchentryof({ taskid, sessionid: session.id, text: input.scratch.append.text ?? "", ...input.scratch.append.stepid !== void 0 && input.scratch.append.stepid.trim() !== "" ? { stepid: input.scratch.append.stepid } : {}, author: "user", now });
21244
+ await memory.appendscratchentry(entry);
21245
+ await audit("scratchpad", `The user appended one scratchpad entry to the task ${taskid}${entry.stepid !== void 0 ? ` beside the step ${entry.stepid}` : ""}; the pad stays append only.`, { sessionid: session.id, planid: taskid });
21246
+ return { ...await sessionviewof(), entry };
21247
+ }
21248
+ if (input.scratch.read !== void 0) return { scratchpad: await memory.readscratchpad(taskid, session.id) };
21249
+ }
21250
+ if (input.summary !== void 0) {
21251
+ if (input.summary.read !== void 0) {
21252
+ const runid = input.summary.read.runid?.trim() || plan?.id || "";
21253
+ const summary = await memory.getrunsummary(runid);
21254
+ if (!summary) throw new Error(`No run summary exists for the run ${runid}.`);
21255
+ return { summary };
21256
+ }
21257
+ if (input.summary.list !== void 0) return { summaries: await memory.listrunsummaries(input.summary.list.origin?.trim() || void 0) };
21258
+ }
21259
+ if (input.recall !== void 0 && input.recall.query !== void 0) {
21260
+ const text2 = input.recall.query.text?.trim() ?? "";
21261
+ if (text2 === "") throw new Error("The semantic recall query needs its text.");
21262
+ const scope = session ? [.../* @__PURE__ */ new Set([session.origin, ...session.grants ?? []])] : [];
21263
+ const scopegate2 = semanticrecallscopegate({ origin: input.recall.query.origin?.trim() || void 0, scope });
21264
+ if (!scopegate2.allowed) throw new Error(scopegate2.reason);
21265
+ const matches = await memory.semanticrecall({ text: text2, ...input.recall.query.origin !== void 0 && input.recall.query.origin.trim() !== "" ? { origin: input.recall.query.origin.trim() } : {}, ...input.recall.query.limit !== void 0 ? { limit: input.recall.query.limit } : {} }, { origins: scope }, rankrecall);
21266
+ await audit("recall", `The semantic recall ranked ${matches.length} past extraction${matches.length === 1 ? "" : "s"} by text similarity inside the ${scope.length} origin scope${scope.length === 1 ? "" : "s"} of the run; every match carries its run and step provenance.`, { ...session ? { sessionid: session.id } : {} });
21267
+ return { matches };
21268
+ }
21269
+ if (input.correction !== void 0 && input.correction.list !== void 0) {
21270
+ const readgate = memoryreadscopegate({ phase: plan && plan.state === "pending" ? "planning" : "prompting" });
21271
+ if (!readgate.allowed) throw new Error(readgate.reason);
21272
+ return { corrections: await memory.getcorrections({ ...input.correction.list.origin !== void 0 ? { origin: input.correction.list.origin } : {}, ...input.correction.list.kind !== void 0 ? { kind: input.correction.list.kind } : {} }) };
21273
+ }
21274
+ if (input.consent !== void 0 && input.consent.list !== void 0) {
21275
+ const readgate = memoryreadscopegate({ phase: "prompting" });
21276
+ if (!readgate.allowed) throw new Error(readgate.reason);
21277
+ const origin = input.consent.list.origin?.trim() || session?.origin || "";
21278
+ const entries = await memory.getconsentmemory(origin === "" ? void 0 : origin);
21279
+ const advisory = consentadvisoryverdict(entries, origin, "observe");
21280
+ return { entries, advisory: advisory.reason };
21281
+ }
21282
+ if (input.grid !== void 0) {
21283
+ if (input.grid.rows !== void 0) return { grid: (await sessionviewof()).grid };
21284
+ if (input.grid.open !== void 0) {
21285
+ const runid = input.grid.open.runid?.trim() ?? "";
21286
+ const view = await sessionviewof();
21287
+ const row = view.grid.find((candidate) => candidate.runid === runid);
21288
+ if (!row) throw new Error(`No session grid row exists for the run ${runid}.`);
21289
+ if (row.tabid !== void 0) await chrome.sidePanel.open({ tabId: row.tabid }).catch(() => {
21290
+ });
21291
+ await audit("session", `The user opened the session grid row of the run ${runid} from the interface deep link.`, { ...session ? { sessionid: session.id } : {}, planid: runid });
21292
+ return { opened: runid };
21293
+ }
21294
+ if (input.grid.resume !== void 0) {
21295
+ const runid = input.grid.resume.runid?.trim() ?? "";
21296
+ if (!session) throw new Error("The resume needs its active session.");
21297
+ if (session.pausedat === void 0) throw new Error("The session of the run stays active; nothing to resume.");
21298
+ const { pausedat, ...resumedsession } = session;
21299
+ void pausedat;
21300
+ await memory.setsession(resumedsession);
21301
+ await audit("resume", `The user resumed the paused session of the run ${runid} from the session grid.`, { sessionid: session.id, planid: runid });
21302
+ return { ...await sessionviewof(), resumed: runid };
21303
+ }
21304
+ if (input.grid.reopen !== void 0) {
21305
+ const runid = input.grid.reopen.runid?.trim() ?? "";
21306
+ const log = await memory.getimmutablelog(runid);
21307
+ if (!log) throw new Error(`No sealed run exists for the run ${runid}.`);
21308
+ const read = await readverifiedlog(log);
21309
+ if (!read.ok) throw new Error(read.reason);
21310
+ await audit("session", `The user reopened the sealed run ${runid} from the session grid; the chain verification passed and the log link stays intact.`, { ...session ? { sessionid: session.id } : {}, planid: runid });
21311
+ return { reopened: runid, entries: read.entries.length, ...log.seal !== void 0 ? { sealhash: log.seal.sealhash.current } : {} };
21312
+ }
21313
+ }
21314
+ if (input.search !== void 0 && input.search.query !== void 0) {
21315
+ if (settings?.historyindex === false) throw new Error("The historysearch index building stays off in the user preferences; the search box needs the index on.");
21316
+ const query = historyqueryof(input.search.query);
21317
+ if (!query) throw new Error("The history search needs its text with a coherent time range.");
21318
+ const hits = await memory.historysearch(query, historysearch);
21319
+ await audit("search", `The history search matched ${hits.length} entr${hits.length === 1 ? "y" : "ies"} of the corpus${query.origin !== void 0 ? ` for ${query.origin}` : ""}${query.outcome !== void 0 ? ` with the outcome ${query.outcome}` : ""}; every hit highlights its matched terms.`, { ...session ? { sessionid: session.id } : {} });
21320
+ return { hits };
21321
+ }
21322
+ if (input.cancel !== void 0) {
21323
+ const runid = input.cancel.runid?.trim() || plan?.id || "";
21324
+ if (runid === "") throw new Error("The cancelrun needs its run.");
21325
+ const progress = await memory.getprogress();
21326
+ const preference = input.cancel.rollback === "none" ? "none" : input.cancel.rollback === "queued" ? "queued" : settings?.cancelrollback;
21327
+ const action = cancelrunactionof({ runid, sessionid: session?.id ?? "", plan: plan && plan.id === runid ? plan : void 0, progress, preference });
21328
+ const split = rollbacksplit(plan && plan.id === runid ? plan : void 0, progress);
21329
+ const cancelgate = cancelrungate({ queuedstepids: action.rollback.queuedstepids, executedstepids: split.executedstepids, rollbackscope: action.rollback.scope });
21330
+ if (!cancelgate.allowed) throw new Error(cancelgate.reason);
21331
+ if (plan && plan.id === runid && ["pending", "approved"].includes(plan.state)) await memory.setplan({ ...plan, state: "cancelled" });
21332
+ if (session) await appendrunevent("cancel", `The user cancelled the run ${runid}: ${action.rollback.label}`, session, session.origin).catch(() => {
21333
+ });
21334
+ await audit("cancel", `The user cancelled the run ${runid}: ${action.rollback.label}`, { ...session ? { sessionid: session.id } : {}, planid: runid });
21335
+ return { ...await sessionviewof(), cancelled: action };
21336
+ }
21337
+ if (input.retry !== void 0) {
21338
+ const stepid = input.retry.stepid?.trim() ?? "";
21339
+ if (stepid === "") throw new Error("The retry needs its step.");
21340
+ const retrygate = retrydispatchgate({ reviewed: true, stepid });
21341
+ if (!retrygate.allowed) throw new Error(retrygate.reason);
21342
+ const output = await executestep(stepid);
21343
+ await audit("retry", `The user retried the step ${stepid} through a new reviewed dispatch: ${output.summary}`, { ...session ? { sessionid: session.id } : {}, ...plan ? { planid: plan.id } : {}, stepid });
21344
+ return output;
21345
+ }
21346
+ if (input.error !== void 0) return { errors: await memory.geterrorsurfaces(input.error.stepid?.trim() || void 0) };
21347
+ if (input.settings !== void 0) {
21348
+ const patch = { ...settings };
21349
+ for (const field of ["noteretention", "scratchpadretention", "summaryretention", "correctionretention", "recallwindow"]) {
21350
+ const value = input.settings[field];
21351
+ if (value === void 0) continue;
21352
+ const gate = sessionretentionvalid(value);
21353
+ if (!gate.allowed) throw new Error(gate.reason);
21354
+ patch[field] = value;
21355
+ }
21356
+ if (input.settings.summarywindow !== void 0) {
21357
+ const windowgate = summarywindowvalid(input.settings.summarywindow);
21358
+ if (!windowgate.allowed) throw new Error(windowgate.reason);
21359
+ patch.summarywindow = input.settings.summarywindow;
21360
+ }
21361
+ if (input.settings.historyindex !== void 0) patch.historyindex = input.settings.historyindex === true;
21362
+ if (input.settings.cancelrollback !== void 0) patch.cancelrollback = input.settings.cancelrollback === "none" ? "none" : "queued";
21363
+ await memory.setsettings(patch);
21364
+ await audit("configure", `The user updated the session interface preferences: notes retention ${patch.noteretention !== void 0 ? `${patch.noteretention} milliseconds` : "every note stays"}, scratchpad retention ${patch.scratchpadretention !== void 0 ? `${patch.scratchpadretention} milliseconds` : "every entry stays"}, summaries retention ${patch.summaryretention !== void 0 ? `${patch.summaryretention} milliseconds` : "every summary stays"}, corrections retention ${patch.correctionretention !== void 0 ? `${patch.correctionretention} milliseconds` : "every correction stays"}, recall window ${patch.recallwindow !== void 0 ? `${patch.recallwindow} milliseconds` : "the whole index"}, summary window ${patch.summarywindow !== void 0 ? `${patch.summarywindow} steps` : "no cap"}, historysearch index ${patch.historyindex !== false ? "on" : "off"} and cancelrun rollback ${patch.cancelrollback ?? "queued"}.`, {});
21365
+ return { ...await sessionviewof(), configured: true };
21366
+ }
21367
+ if (input.bundle !== void 0 && input.bundle.export === true) {
21368
+ const bundle = await memory.exportsessionbundle(now);
21369
+ await audit("export", `The user exported the session audit bundle: ${bundle.notes.length} note${bundle.notes.length === 1 ? "" : "s"}, ${bundle.summaries.length} run summar${bundle.summaries.length === 1 ? "y" : "ies"} and ${bundle.corrections.length} correction${bundle.corrections.length === 1 ? "" : "s"}; sensitive note bodies stay sealed in the export.`, { ...session ? { sessionid: session.id } : {} });
21370
+ return { bundle };
21371
+ }
21372
+ throw new Error("The sessions command carries no note, scratch, summary, recall, correction, consent, grid, search, cancel, retry, error, settings or bundle action.");
21373
+ }
19879
21374
  async function handlerequest(message, sender) {
19880
- if (!extensionpage(sender)) throw new Error("Requests are accepted only from Devthink extension pages.");
21375
+ const originverdict = origincheckof({ ...sender.id !== void 0 ? { senderid: sender.id } : {}, ...sender.origin !== void 0 ? { senderorigin: sender.origin } : {}, extensionid: chrome.runtime.id, connectallow: await memory.getconnectallow() });
21376
+ const inboundgate = origincheckgate({ verdict: originverdict });
21377
+ if (!inboundgate.allowed) {
21378
+ await audit("inbound", `The origincheck dropped an inbound message from ${originverdict.sender}${originverdict.origin !== "" ? ` of ${originverdict.origin}` : ""} without handler execution: ${inboundgate.reason}`, {}).catch(() => {
21379
+ });
21380
+ throw new Error(inboundgate.reason);
21381
+ }
21382
+ if (sender.id === chrome.runtime.id && !extensionpage(sender)) throw new Error("Requests are accepted only from Devthink extension pages.");
21383
+ const schemaerrors = schemavalidation(message);
21384
+ const schemagate = schemaguardgate({ errors: schemaerrors });
21385
+ if (!schemagate.allowed) {
21386
+ await audit("schema", `The schemastrict validation refused an inbound command with ${schemaerrors.length} schema error${schemaerrors.length === 1 ? "" : "s"} at ${schemaerrors.map((error) => error.path).join(", ")}; the refusal echoes no payload.`, {}).catch(() => {
21387
+ });
21388
+ throw new Error(schemagate.reason);
21389
+ }
19881
21390
  const input = message;
19882
21391
  switch (input.kind) {
19883
21392
  case "configure": {
@@ -19997,7 +21506,7 @@ async function handlerequest(message, sender) {
19997
21506
  const livetab = session ? await chrome.tabs.get(session.tabid).catch(() => void 0) : void 0;
19998
21507
  const waitprofile = session ? waitprofiles.find((record2) => record2.origin === session.origin) : void 0;
19999
21508
  const livestate = { phase: livetab?.status === "loading" ? "loading" : "complete", ...navrecords[0] ? { finalurl: navrecords[0].finalurl, redirects: navrecords[0].chain } : {} };
20000
- return { config: await memory.getconfig(), session, plan, progress: plan && progress?.planid === plan.id ? progress : void 0, diagnostic: await memory.getdiagnostic(), audit: await memory.getaudit(), capabilities: await refreshcapabilities(), outcomes: await memory.getoutcomes(), holds: heldkeysreport({ tabid: session?.tabid ?? 0, holds }), dialogs: await memory.getdialogs(), retries: await memory.getretries(), ...signals ? { signals: signalsreport({ signals }) } : { signals: signalsreport({}) }, banners: await memory.getbanners(), mutationevents: await memory.getmutationevents(), focusevents: await memory.getfocusevents(), diffs: await memory.getdiffs(), selectors: await memory.getselectors(), ...a11y ? { a11y } : {}, ...reader ? { reader } : {}, ...map ? { map } : {}, trail: trailreport({ ...session ? { sessionid: session.id } : {}, trail }), navrecords, ratestates, safeties, curated, waitprofiles, auths, navcontrol, navqueues, artifacts, navstate: livestate, ...waitprofile ? { waitprofile } : {}, offline: !navigator.onLine, tabs, windows, layouts: layoutreport({ layouts }), tabgroups, tabmetas, badges, snapshots, closedtabs, tabwatchevents, clones, tasktabgauge: taskgauge, ...controltab ? { controltab } : {}, tabreport: report, profiles, tickets, wizards: wizardreport({ ...session ? { sessionid: session.id } : {}, wizards, picks }), picks, errorreports, captchas, detections, ...codeentry !== void 0 ? { codeentry: true } : {}, datasets, imports, extractsessions, streams, exports, provenances, taskrules, sheetendpoints: sheetgrants, downloads, netlogs, clipconsents, clips, quarantines, cleanuprules, cleanupruns, capturecounters, inventory, mimefilters, scanhooks, captures: capturemetadata, capturepairs, capturepolicy: runsettings?.capturepolicy ?? "manual", media: mediarecords, imagebatches, recordingconsents, recordingactive: [...activerecordings.values()].map((active) => ({ id: active.record.id, kind: active.record.kind, scope: active.record.scope, startedat: active.record.startedat, stopat: active.stopat })), recordingwindow: runsettings?.recordingwindow, calls, endpoints, fetchconsents, apikeys, callretention: runsettings?.callretention, fetchesactive: activefetches.size, exchanges, channels, subscriptions, apimap, messages: messagecount, webrequestgrant: runsettings?.webrequestgrant === true, bodyretention: runsettings?.bodyretention, timelineretention: runsettings?.timelineretention, timeline, consoleconsents: await memory.getconsoleconsents(), rotationtargets: await memory.getrotationtargets(), levelsummaries: await memory.getlevelsummaries(), cdpsessions: await memory.getcdpsessions(), cdpcommands: await memory.getcdpcommands(), cdpeventrules: await memory.getcdpeventrules(), breakpoints: await memory.getbreakpoints(), pauses: await memory.getpauses(), watchexpressions: await memory.getwatchexpressions(), scriptoverrides: await memory.getscriptoverrides(), debuggergrants: await memory.getdebuggergrants(), pauseretention: runsettings?.pauseretention, breakpointceiling: runsettings?.breakpointceiling, cdpattached: [...activecdpsessions.values()].filter((active) => active.session.detachedat === void 0).length, profileretention: runsettings?.profileretention, traceceiling: runsettings?.traceceiling, profile: profilereport({ flows: await memory.getflowmetrics(), heaps: await memory.getheaprecords(), samples: await memory.getgrowsamples(), trends: await memory.gettrends(), profiles: await memory.getcpuprofiles(), shifts: await memory.getshiftentries(), traces: await memory.gettracerecords(), sourcemaps: await memory.getsourcemaps(), consents: await memory.getsourcemapconsents() }), profileactive: activememorytrackers.size + activeprofiletargets.size, profiletargets: [...activeprofiletargets.values()].flatMap((entry) => entry.targets), socketsactive: activesockets.size, emulation: emulationreport({ ...plan && await loademulationstate(plan.id) !== void 0 ? { state: await loademulationstate(plan.id) } : {}, devices: await memory.getdevicepresets(), networks: await memory.getnetworkpresets(), locations: await memory.getlocationpresets(), agents: await memory.getagentpresets(), blackbox: await memory.getblackboxrules(), permissions: await memory.getpermissionoverrides(), consents: await memory.getlocationconsents() }), emulatedlayers: plan ? layernames(await loademulationstate(plan.id)) : [], emulationretention: runsettings?.emulationretention, traffic, tokens, authflows, activerules: [...activerules.values()].reduce((total, ruleset) => total + ruleset.blocks.filter((rule) => rule.revertedat === void 0).length + ruleset.mocks.filter((rule) => rule.revertedat === void 0).length + ruleset.rewrites.filter((rule) => rule.revertedat === void 0).length + (ruleset.proxy !== void 0 && ruleset.proxy.revertedat === void 0 ? 1 : 0), 0), sessionmemory: sessionreport({ records: sessionrecords, events: await memory.getsessionevents(), folders: await memory.getsessionfolders(), diffs: await memory.getsessiondiffs(), ...autosnapshot !== void 0 ? { auto: autosnapshot.interval } : {}, ...crashed ? { crashed: true } : {} }), autosnapshotstate: autosnapshot, sessionretention: runsettings?.sessionretention, trigger: triggerlist({ rules: await memory.gettriggerules(), workflows: await memory.listworkflows(), queue: await memory.gettriggerqueue() }), triggerretention: runsettings?.triggerretention, workflow: workflowreport({ workflows: await memory.listworkflows(), runs: await memory.listworkflowruns(), templates: await memory.getsteptemplates(), ...newestworkflowrun !== void 0 ? { log: await memory.getrunlog(newestworkflowrun.id), scopes: await memory.getrunscopes(newestworkflowrun.id), provenance: await memory.getworkflowprovenance(newestworkflowrun.id), control: await memory.listcontroldecisions(newestworkflowrun.id) } : {} }), runlogretention: runsettings?.runlogretention, runhistoryretention: runsettings?.runhistoryretention, editor: editorstate({ versions: await memory.listworkflowversions(), diffs: await memory.listversiondiffs(), history: await memory.gethistory(), overrides: await memory.listsiteoverrides(), imports: (await memory.listworkflowimports()).map((entry) => ({ id: entry.id, workflowid: entry.record.id, name: entry.record.name, version: entry.record.version, steps: entry.record.steps.length, risk: entry.record.risk, importedat: entry.importedat, ...entry.filename !== void 0 ? { filename: entry.filename } : {} })), backgroundruns: await memory.getbackgroundruns(), watchdog: { ...runsettings?.watchdog !== void 0 ? { config: runsettings.watchdog } : {}, events: await memory.listwatchdogevents() } }), ...taskstate !== void 0 ? { taskstate } : {}, ...stitchprogress.size > 0 ? { stitchprogress: [...stitchprogress.values()] } : {}, mcp: await mcpstateof(), llm: await llmstateof(), swarm: await swarmstateof(), environments: await environmentviewof(), security: await securityviewof() };
21509
+ return { config: await memory.getconfig(), session, plan, progress: plan && progress?.planid === plan.id ? progress : void 0, diagnostic: await memory.getdiagnostic(), audit: await memory.getaudit(), capabilities: await refreshcapabilities(), outcomes: await memory.getoutcomes(), holds: heldkeysreport({ tabid: session?.tabid ?? 0, holds }), dialogs: await memory.getdialogs(), retries: await memory.getretries(), ...signals ? { signals: signalsreport({ signals }) } : { signals: signalsreport({}) }, banners: await memory.getbanners(), mutationevents: await memory.getmutationevents(), focusevents: await memory.getfocusevents(), diffs: await memory.getdiffs(), selectors: await memory.getselectors(), ...a11y ? { a11y } : {}, ...reader ? { reader } : {}, ...map ? { map } : {}, trail: trailreport({ ...session ? { sessionid: session.id } : {}, trail }), navrecords, ratestates, safeties, curated, waitprofiles, auths, navcontrol, navqueues, artifacts, navstate: livestate, ...waitprofile ? { waitprofile } : {}, offline: !navigator.onLine, tabs, windows, layouts: layoutreport({ layouts }), tabgroups, tabmetas, badges, snapshots, closedtabs, tabwatchevents, clones, tasktabgauge: taskgauge, ...controltab ? { controltab } : {}, tabreport: report, profiles, tickets, wizards: wizardreport({ ...session ? { sessionid: session.id } : {}, wizards, picks }), picks, errorreports, captchas, detections, ...codeentry !== void 0 ? { codeentry: true } : {}, datasets, imports, extractsessions, streams, exports, provenances, taskrules, sheetendpoints: sheetgrants, downloads, netlogs, clipconsents, clips, quarantines, cleanuprules, cleanupruns, capturecounters, inventory, mimefilters, scanhooks, captures: capturemetadata, capturepairs, capturepolicy: runsettings?.capturepolicy ?? "manual", media: mediarecords, imagebatches, recordingconsents, recordingactive: [...activerecordings.values()].map((active) => ({ id: active.record.id, kind: active.record.kind, scope: active.record.scope, startedat: active.record.startedat, stopat: active.stopat })), recordingwindow: runsettings?.recordingwindow, calls, endpoints, fetchconsents, apikeys, callretention: runsettings?.callretention, fetchesactive: activefetches.size, exchanges, channels, subscriptions, apimap, messages: messagecount, webrequestgrant: runsettings?.webrequestgrant === true, bodyretention: runsettings?.bodyretention, timelineretention: runsettings?.timelineretention, timeline, consoleconsents: await memory.getconsoleconsents(), rotationtargets: await memory.getrotationtargets(), levelsummaries: await memory.getlevelsummaries(), cdpsessions: await memory.getcdpsessions(), cdpcommands: await memory.getcdpcommands(), cdpeventrules: await memory.getcdpeventrules(), breakpoints: await memory.getbreakpoints(), pauses: await memory.getpauses(), watchexpressions: await memory.getwatchexpressions(), scriptoverrides: await memory.getscriptoverrides(), debuggergrants: await memory.getdebuggergrants(), pauseretention: runsettings?.pauseretention, breakpointceiling: runsettings?.breakpointceiling, cdpattached: [...activecdpsessions.values()].filter((active) => active.session.detachedat === void 0).length, profileretention: runsettings?.profileretention, traceceiling: runsettings?.traceceiling, profile: profilereport({ flows: await memory.getflowmetrics(), heaps: await memory.getheaprecords(), samples: await memory.getgrowsamples(), trends: await memory.gettrends(), profiles: await memory.getcpuprofiles(), shifts: await memory.getshiftentries(), traces: await memory.gettracerecords(), sourcemaps: await memory.getsourcemaps(), consents: await memory.getsourcemapconsents() }), profileactive: activememorytrackers.size + activeprofiletargets.size, profiletargets: [...activeprofiletargets.values()].flatMap((entry) => entry.targets), socketsactive: activesockets.size, emulation: emulationreport({ ...plan && await loademulationstate(plan.id) !== void 0 ? { state: await loademulationstate(plan.id) } : {}, devices: await memory.getdevicepresets(), networks: await memory.getnetworkpresets(), locations: await memory.getlocationpresets(), agents: await memory.getagentpresets(), blackbox: await memory.getblackboxrules(), permissions: await memory.getpermissionoverrides(), consents: await memory.getlocationconsents() }), emulatedlayers: plan ? layernames(await loademulationstate(plan.id)) : [], emulationretention: runsettings?.emulationretention, traffic, tokens, authflows, activerules: [...activerules.values()].reduce((total, ruleset) => total + ruleset.blocks.filter((rule) => rule.revertedat === void 0).length + ruleset.mocks.filter((rule) => rule.revertedat === void 0).length + ruleset.rewrites.filter((rule) => rule.revertedat === void 0).length + (ruleset.proxy !== void 0 && ruleset.proxy.revertedat === void 0 ? 1 : 0), 0), sessionmemory: sessionreport({ records: sessionrecords, events: await memory.getsessionevents(), folders: await memory.getsessionfolders(), diffs: await memory.getsessiondiffs(), ...autosnapshot !== void 0 ? { auto: autosnapshot.interval } : {}, ...crashed ? { crashed: true } : {} }), autosnapshotstate: autosnapshot, sessionretention: runsettings?.sessionretention, trigger: triggerlist({ rules: await memory.gettriggerules(), workflows: await memory.listworkflows(), queue: await memory.gettriggerqueue() }), triggerretention: runsettings?.triggerretention, workflow: workflowreport({ workflows: await memory.listworkflows(), runs: await memory.listworkflowruns(), templates: await memory.getsteptemplates(), ...newestworkflowrun !== void 0 ? { log: await memory.getrunlog(newestworkflowrun.id), scopes: await memory.getrunscopes(newestworkflowrun.id), provenance: await memory.getworkflowprovenance(newestworkflowrun.id), control: await memory.listcontroldecisions(newestworkflowrun.id) } : {} }), runlogretention: runsettings?.runlogretention, runhistoryretention: runsettings?.runhistoryretention, editor: editorstate({ versions: await memory.listworkflowversions(), diffs: await memory.listversiondiffs(), history: await memory.gethistory(), overrides: await memory.listsiteoverrides(), imports: (await memory.listworkflowimports()).map((entry) => ({ id: entry.id, workflowid: entry.record.id, name: entry.record.name, version: entry.record.version, steps: entry.record.steps.length, risk: entry.record.risk, importedat: entry.importedat, ...entry.filename !== void 0 ? { filename: entry.filename } : {} })), backgroundruns: await memory.getbackgroundruns(), watchdog: { ...runsettings?.watchdog !== void 0 ? { config: runsettings.watchdog } : {}, events: await memory.listwatchdogevents() } }), ...taskstate !== void 0 ? { taskstate } : {}, ...stitchprogress.size > 0 ? { stitchprogress: [...stitchprogress.values()] } : {}, mcp: await mcpstateof(), llm: await llmstateof(), swarm: await swarmstateof(), environments: await environmentviewof(), security: await securityviewof(), sessionview: await sessionviewof(), sessionpreferences: { ...runsettings?.recallwindow !== void 0 ? { recallwindow: runsettings.recallwindow } : {}, ...runsettings?.noteretention !== void 0 ? { noteretention: runsettings.noteretention } : {}, ...runsettings?.scratchpadretention !== void 0 ? { scratchpadretention: runsettings.scratchpadretention } : {}, ...runsettings?.summaryretention !== void 0 ? { summaryretention: runsettings.summaryretention } : {}, ...runsettings?.correctionretention !== void 0 ? { correctionretention: runsettings.correctionretention } : {}, ...runsettings?.summarywindow !== void 0 ? { summarywindow: runsettings.summarywindow } : {}, ...runsettings?.historyindex !== void 0 ? { historyindex: runsettings.historyindex } : {}, ...runsettings?.cancelrollback !== void 0 ? { cancelrollback: runsettings.cancelrollback } : {} } };
20001
21510
  }
20002
21511
  case "capabilities":
20003
21512
  return refreshcapabilities();
@@ -20026,7 +21535,12 @@ async function handlerequest(message, sender) {
20026
21535
  const rejected = { ...plan, state: "rejected" };
20027
21536
  await memory.setplan(rejected);
20028
21537
  const current = await memory.getsession();
21538
+ for (const step of plan.steps) {
21539
+ await memory.addcorrection(rejectedcorrectionof({ origin: current?.origin ?? "", kind: step.kind, stepid: step.id, original: JSON.stringify({ kind: step.kind, target: step.target, value: step.value, summary: step.summary }), reason: "The user rejected the reviewed plan during plan review.", now: Date.now() })).catch(() => {
21540
+ });
21541
+ }
20029
21542
  await audit("approval", "The user rejected the plan.", { ...current ? { sessionid: current.id } : {}, planid: rejected.id });
21543
+ await audit("correction", `The rejection captured ${plan.steps.length} correction entr${plan.steps.length === 1 ? "y" : "ies"} in the correction memory, one per rejected step with its rejection reason.`, { ...current ? { sessionid: current.id } : {}, planid: rejected.id });
20030
21544
  return rejected;
20031
21545
  }
20032
21546
  case "preview":
@@ -22383,6 +23897,14 @@ async function handlerequest(message, sender) {
22383
23897
  await memory.setplan(plan);
22384
23898
  await memory.setprogress(resetforplan(await memory.getprogress(), plan, Date.now()));
22385
23899
  await memory.setreplans(replans.map((candidate) => candidate.id === replan.id ? { ...candidate, state: "approved" } : candidate));
23900
+ const originaltail = draft.steps.filter((step) => !replan.completedstepids.includes(step.id));
23901
+ for (let index = 0; index < originaltail.length && index < replan.tail.length; index += 1) {
23902
+ const before = originaltail[index];
23903
+ const after = replan.tail[index];
23904
+ if (before === void 0 || after === void 0) continue;
23905
+ await memory.addcorrection(editedcorrectionof({ origin: session?.origin ?? "", kind: after.kind, stepid: after.id, original: JSON.stringify({ kind: before.kind, target: before.target, value: before.value, summary: before.summary }), corrected: JSON.stringify({ kind: after.kind, target: after.target, value: after.value, summary: after.summary }), reason: `The plan review replaced the failed tail step ${before.id} with the revised step ${after.id} of the replan ${replan.id}.`, now: Date.now() })).catch(() => {
23906
+ });
23907
+ }
22386
23908
  await audit("model", `The user approved the fresh review of the replan ${replan.id}: ${completed.length} completed step${completed.length === 1 ? "" : "s"} stay and the ${replan.tail.length} revised step${replan.tail.length === 1 ? "" : "s"} became the changed tail of a pending plan that still passes the same plan review.`, { planid: plan.id, ...session ? { sessionid: session.id } : {} });
22387
23909
  return llmstateof();
22388
23910
  }
@@ -23048,6 +24570,14 @@ async function handlerequest(message, sender) {
23048
24570
  }
23049
24571
  throw new Error("The swarm merge request carries no merge, report, export, compare, lesson, costs, timeline, replay or snapshot action.");
23050
24572
  }
24573
+ case "transparency": {
24574
+ const view = await memory.gettransparencyview();
24575
+ const report = transparencyreport({ grants: transparencygrants({ allowlist: view.allowlist, profiles: view.profiles }), windows: windowhistory(view.windows), connectallow: connectallowlist(view.connectallow), permdiffs: view.permdiffs, safedefaults: view.safedefaults, vault: vaultview(view.vault) });
24576
+ await audit("transparency", `The transparencypage read its transparency report in one memory read: ${report.grants.length} grant row${report.grants.length === 1 ? "" : "s"} with revoke actions, ${report.windows.length} consent window${report.windows.length === 1 ? "" : "s"}, ${report.connectallow.length} connectallow entr${report.connectallow.length === 1 ? "y" : "ies"}, ${report.permdiffs.length} permdiff record${report.permdiffs.length === 1 ? "" : "s"} and ${report.vault.length} vault label${report.vault.length === 1 ? "" : "s"}.`, {});
24577
+ return report;
24578
+ }
24579
+ case "sessions":
24580
+ return handlesessionscommand(message);
23051
24581
  case "security": {
23052
24582
  const input2 = message;
23053
24583
  const now = Date.now();
@@ -23078,6 +24608,8 @@ async function handlerequest(message, sender) {
23078
24608
  const existing = profiles.find((candidate) => candidate.origin === origin);
23079
24609
  const updated = profilekind({ profile: existing ?? originprofileof({ origin, now }), kind, decision, now });
23080
24610
  await memory.saveoriginprofile(updated);
24611
+ if (decision === "deny") await memory.addconsentmemoryentry(consentmemoryof({ origin, decision: "deny", boundary: "the origin profile the user edits", kinds: [kind], now })).catch(() => {
24612
+ });
23081
24613
  await audit("grant", `The origin profile of ${origin} now ${decision === "grant" ? "grants" : "denies"} the ${kind} kind the user reviewed; ${updated.grants.length} grant${updated.grants.length === 1 ? "" : "s"} and ${updated.denials.length} denial${updated.denials.length === 1 ? "" : "s"} on the origin.`, { ...session ? { sessionid: session.id } : {} });
23082
24614
  return { ...await securityviewof(), profile: updated };
23083
24615
  }
@@ -23092,6 +24624,8 @@ async function handlerequest(message, sender) {
23092
24624
  const kinds = (input2.consent.open.kinds ?? []).map((kind) => kind.trim()).filter((kind) => kind !== "");
23093
24625
  const window2 = openconsentwindow({ sessionid: session.id, origin, duration, kinds: kinds.length > 0 ? kinds : ["observe"], now });
23094
24626
  await memory.setconsentwindows([window2, ...(await memory.getconsentwindows()).map((candidate) => candidate.sessionid === session.id && candidate.origin === origin && candidate.state === "active" ? { ...candidate, state: "closed", closedat: now } : candidate)]);
24627
+ await memory.addconsentmemoryentry(consentmemoryof({ origin, decision: "grant", boundary: window2.boundary, kinds: window2.kinds, expiresat: window2.expiresat, now })).catch(() => {
24628
+ });
23095
24629
  await appendrunevent("grant", `The consent prompt opened the window ${window2.id} for ${origin} with the boundary ${window2.boundary}.`, session, origin).catch(() => {
23096
24630
  });
23097
24631
  await audit("grant", `The user answered the consent prompt for ${origin} with the window ${window2.id} and the boundary ${window2.boundary}; no grant ever outlives its named boundary.`, { sessionid: session.id });
@@ -23108,6 +24642,8 @@ async function handlerequest(message, sender) {
23108
24642
  if (!durationgate.allowed) throw new Error(durationgate.reason);
23109
24643
  const { renewed, closed } = renewconsentwindow({ window: current, duration, kinds: current.kinds, now });
23110
24644
  await memory.setconsentwindows([renewed, closed, ...(await memory.getconsentwindows()).filter((candidate) => candidate.id !== windowid)]);
24645
+ await memory.addconsentmemoryentry(consentmemoryof({ origin: current.origin, decision: "grant", boundary: renewed.boundary, kinds: renewed.kinds, expiresat: renewed.expiresat, now })).catch(() => {
24646
+ });
23111
24647
  await appendrunevent("grant", `The consent window of ${current.origin} renewed through a new explicit prompt with the boundary ${renewed.boundary}; the old window stays closed in the history.`, session, current.origin).catch(() => {
23112
24648
  });
23113
24649
  await audit("grant", `The user renewed the consent window of ${current.origin} through a new explicit prompt with the boundary ${renewed.boundary}.`, { sessionid: session.id });
@@ -23136,6 +24672,8 @@ async function handlerequest(message, sender) {
23136
24672
  const queued = (plan2?.steps ?? []).map((step) => step.id).filter((id) => !completed.has(id));
23137
24673
  const revocation = revokerun({ sessionid: session.id, runid, ...pendingstepid !== void 0 ? { pendingstepid } : {}, ...queued.length > 0 ? { queuedstepids: queued } : {}, actor: "user", ...input2.revoke.reason !== void 0 ? { reason: input2.revoke.reason } : {}, now });
23138
24674
  await memory.addrevocation(revocation);
24675
+ await memory.addconsentmemoryentry(consentmemoryof({ origin: session.origin, decision: "revoke", boundary: "the mid run revocation of the user", kinds: ["observe"], now })).catch(() => {
24676
+ });
23139
24677
  if (plan2 && plan2.id === runid && ["pending", "approved"].includes(plan2.state)) await memory.setplan({ ...plan2, state: "cancelled" });
23140
24678
  if (plan2 && plan2.id === runid && pendingstepid !== void 0) await memory.setprogress(recordrevocation(progress, runid, pendingstepid, { haltedstepids: revocation.haltedstepids, revokedstepid: pendingstepid, reason: revocation.reason }, now));
23141
24679
  await appendrunevent("revoke", `The user revoked the run ${runid}: the pending step ${pendingstepid ?? "none"} and every queued step halted without executing (${revocation.haltedstepids.join(", ")}).`, session, session.origin, pendingstepid).catch(() => {
@@ -23185,10 +24723,103 @@ async function handlerequest(message, sender) {
23185
24723
  }
23186
24724
  if (input2.settings.logretention !== void 0) patch.logretention = input2.settings.logretention;
23187
24725
  if (input2.settings.maskshapes !== void 0) patch.maskshapes = input2.settings.maskshapes.map((shape) => shape.trim().toLowerCase()).filter((shape) => shape !== "");
24726
+ if (input2.settings.phishdistance !== void 0) {
24727
+ const thresholdgate = phishthresholdgate(input2.settings.phishdistance);
24728
+ if (!thresholdgate.allowed) throw new Error(thresholdgate.reason);
24729
+ patch.phishdistance = input2.settings.phishdistance;
24730
+ }
24731
+ if (input2.settings.phishfreshness !== void 0) patch.phishfreshness = input2.settings.phishfreshness;
23188
24732
  await memory.setsettings(patch);
23189
24733
  await audit("configure", `The user updated the security settings: consent duration ${patch.consentduration !== void 0 ? `${patch.consentduration} milliseconds` : "the prompt asks every time"}, log retention ${patch.logretention !== void 0 ? `${patch.logretention} milliseconds` : "every sealed log stays"}, mask shapes ${patch.maskshapes?.length ?? 0} configured.`, {});
23190
24734
  return { ...await securityviewof(), configured: true };
23191
24735
  }
24736
+ if (input2.gate !== void 0 && input2.gate.resolve !== void 0) {
24737
+ const gateid = input2.gate.resolve.gateid?.trim() ?? "";
24738
+ const decision = input2.gate.resolve.decision === "refused" ? "refused" : "resolved";
24739
+ if (gateid === "") throw new Error("The gate resolution names its single gate.");
24740
+ const resolved = resolvegate({ gates: await memory.getgates(), gateid, decision, actor: "user", now });
24741
+ if (resolved.resolution === void 0 || resolved.gates === void 0) throw new Error(`No open gate ${gateid} exists to resolve; a gate resolution stays a distinct human action on one gate.`);
24742
+ await memory.setgates(resolved.gates);
24743
+ await memory.addgateresolution(resolved.resolution);
24744
+ const gateplan = await memory.getplan();
24745
+ const gate = resolved.gates.find((candidate) => candidate.gateid === gateid);
24746
+ if (gateplan && gate?.resolvedat !== void 0) await memory.setprogress(recordgatewait(await memory.getprogress(), gateplan.id, gate.stepid, { gateid: gate.gateid, kind: gate.kind, openedat: gate.openedat, resolvedat: gate.resolvedat, waitedms: Math.max(0, gate.resolvedat - gate.openedat) }, now)).catch(() => {
24747
+ });
24748
+ if (session) await appendrunevent("gate", `The user ${decision === "resolved" ? "resolved" : "refused"} the ${resolved.resolution.kind} gate ${gateid} of the step ${resolved.resolution.stepid} through one distinct human action; no timeout resolved it and no batch approved it.`, session, gate?.origin ?? session.origin, resolved.resolution.stepid).catch(() => {
24749
+ });
24750
+ await audit("gate", `The user ${decision === "resolved" ? "resolved" : "refused"} the ${resolved.resolution.kind} gate ${gateid} of the step ${resolved.resolution.stepid} through one distinct human action; no timeout resolved it and no batch approved it.`, { ...session ? { sessionid: session.id } : {}, ...gateplan ? { planid: gateplan.id } : {}, stepid: resolved.resolution.stepid });
24751
+ return { ...await securityviewof(), gate };
24752
+ }
24753
+ if (input2.vault !== void 0) {
24754
+ if (input2.vault.add !== void 0) {
24755
+ const label = input2.vault.add.label?.trim() ?? "";
24756
+ const scope = input2.vault.add.scope?.trim() !== "" && input2.vault.add.scope !== void 0 ? input2.vault.add.scope.trim() : session?.origin ?? "";
24757
+ const value = input2.vault.add.value ?? "";
24758
+ if (label === "" || scope === "" || value === "") throw new Error("The vault entry needs its label, its exact origin scope and its value; the value stays behind the vault seam.");
24759
+ const entry = await vaultstore({ seam: vaultseamstore, label, scope, profileid: runstateprofile, provenance: input2.vault.add.provenance === "session" ? "session" : "user", value, now });
24760
+ await memory.addsecret(entry);
24761
+ await audit("vault", `The user stored the secret ${entry.label} for ${entry.scope} behind the vault seam; the metadata keeps the label, the scope, the provenance and the digest while no plaintext value persists anywhere.`, { ...session ? { sessionid: session.id } : {} });
24762
+ return { ...await securityviewof(), secret: { vaultid: entry.vaultid, label: entry.label, scope: entry.scope } };
24763
+ }
24764
+ if (input2.vault.delete !== void 0) {
24765
+ const vaultid = input2.vault.delete.vaultid?.trim() ?? "";
24766
+ const entry = (await memory.getsecretvault()).find((candidate) => candidate.vaultid === vaultid);
24767
+ if (!entry) throw new Error(`No vault entry ${vaultid} exists.`);
24768
+ const dropped = await vaultdelete({ seam: vaultseamstore, entry });
24769
+ await memory.removesecret(vaultid);
24770
+ await audit("vault", `The user deleted the secret ${dropped.label} of ${entry.scope}: ${dropped.reason}`, { ...session ? { sessionid: session.id } : {} });
24771
+ return { ...await securityviewof(), removedsecret: vaultid };
24772
+ }
24773
+ }
24774
+ if (input2.connectallow !== void 0) {
24775
+ if (input2.connectallow.add !== void 0) {
24776
+ const entry = connectallowentryof({ senderid: input2.connectallow.add.senderid?.trim() ?? "", displayname: input2.connectallow.add.displayname?.trim() ?? "", ...input2.connectallow.add.origin !== void 0 && input2.connectallow.add.origin.trim() !== "" ? { origin: input2.connectallow.add.origin.trim() } : {}, now });
24777
+ await memory.addconnectallow(entry);
24778
+ await audit("inbound", `The user allowed the external sender ${entry.displayname} (${entry.senderid})${entry.origin !== void 0 ? ` of ${entry.origin}` : ""}; the connectallow list ships empty by default and holds user managed entries only.`, { ...session ? { sessionid: session.id } : {} });
24779
+ return { ...await securityviewof(), allowedsender: entry };
24780
+ }
24781
+ if (input2.connectallow.remove !== void 0) {
24782
+ const senderid = input2.connectallow.remove.senderid?.trim() ?? "";
24783
+ await memory.removeconnectallow(senderid);
24784
+ await audit("inbound", `The user removed the external sender ${senderid} from the connectallow list; the origincheck drops its messages and ports again.`, { ...session ? { sessionid: session.id } : {} });
24785
+ return { ...await securityviewof(), removedsender: senderid };
24786
+ }
24787
+ }
24788
+ if (input2.ratelimit !== void 0) {
24789
+ if (input2.ratelimit.set !== void 0) {
24790
+ const origin = input2.ratelimit.set.origin?.trim() ?? "";
24791
+ const limit = input2.ratelimit.set.limit ?? 0;
24792
+ const window2 = input2.ratelimit.set.window ?? 0;
24793
+ if (origin === "") throw new Error("The ratelimit bucket needs its exact origin.");
24794
+ const bounds = ratelimitboundsvalid(limit, window2);
24795
+ if (!bounds.allowed) throw new Error(bounds.reason);
24796
+ const bucket = bucketof({ origin, sessionid: session?.id ?? "global", limit, window: window2, now });
24797
+ await memory.saveratelimitbucket(bucket);
24798
+ await audit("rate", `The user configured the ratelimit bucket of ${origin} at ${limit} command${limit === 1 ? "" : "s"} per ${window2} milliseconds; the bounds stay user choices with no hidden ceiling.`, { ...session ? { sessionid: session.id } : {} });
24799
+ return { ...await securityviewof(), bucket };
24800
+ }
24801
+ if (input2.ratelimit.remove !== void 0) {
24802
+ const origin = input2.ratelimit.remove.origin?.trim() ?? "";
24803
+ const buckets = await memory.getratelimitbuckets();
24804
+ for (const bucket of buckets.filter((candidate) => candidate.origin === origin)) await memory.removeratelimitbucket(bucket.origin, bucket.sessionid);
24805
+ await audit("rate", `The user removed the ratelimit bucket of ${origin}; the origin runs without a bucket because the bounds stay user choices only.`, { ...session ? { sessionid: session.id } : {} });
24806
+ return { ...await securityviewof(), removedbucket: origin };
24807
+ }
24808
+ }
24809
+ if (input2.redact !== void 0) {
24810
+ if (input2.redact.add !== void 0) {
24811
+ const region = regionof({ origin: input2.redact.add.origin?.trim() !== "" && input2.redact.add.origin !== void 0 ? input2.redact.add.origin.trim() : session?.origin ?? "", template: input2.redact.add.template?.trim() !== "" && input2.redact.add.template !== void 0 ? input2.redact.add.template.trim() : "page", x: input2.redact.add.x ?? 0, y: input2.redact.add.y ?? 0, width: input2.redact.add.width ?? 0, height: input2.redact.add.height ?? 0, reason: input2.redact.add.reason?.trim() !== "" && input2.redact.add.reason !== void 0 ? input2.redact.add.reason.trim() : "The user drew the mask on the capture surface.", source: "userdrawn", now });
24812
+ await memory.addredactregion(region);
24813
+ await audit("capture", `The user drew the redact region ${region.id} at ${region.x},${region.y} of ${region.width}x${region.height} on ${region.origin}/${region.template}: ${region.reason}`, { ...session ? { sessionid: session.id } : {} });
24814
+ return { ...await securityviewof(), region };
24815
+ }
24816
+ if (input2.redact.remove !== void 0) {
24817
+ const id = input2.redact.remove.id?.trim() ?? "";
24818
+ await memory.removeredactregion(id);
24819
+ await audit("capture", `The user removed the redact region ${id}.`, { ...session ? { sessionid: session.id } : {} });
24820
+ return { ...await securityviewof(), removedregion: id };
24821
+ }
24822
+ }
23192
24823
  const plan = await memory.getplan();
23193
24824
  const pending = [];
23194
24825
  if (session && plan && ["pending", "approved"].includes(plan.state)) {
@@ -23646,7 +25277,7 @@ async function raiseremoteapproval(clientid, toolname, params, step) {
23646
25277
  return { content: `The approval gate ${request.id} holds the ${toolname} call; it executes once the user approves it in the panel.`, payload: { approvalid: request.id, state: "pending", ...request.timeoutat !== void 0 ? { timeoutat: request.timeoutat } : {} }, iserror: false };
23647
25278
  }
23648
25279
  async function executelistruns(step, session) {
23649
- const options = stepoptions3(step);
25280
+ const options = stepoptions6(step);
23650
25281
  const statefilter = typeof options.state === "string" && options.state.trim() !== "" ? options.state : void 0;
23651
25282
  const runs = await memory.listworkflowruns();
23652
25283
  const selected = statefilter !== void 0 ? runs.filter((run) => run.state === statefilter) : runs;
@@ -24021,7 +25652,7 @@ async function maybeautosnapshot() {
24021
25652
  await audit("session", `The reviewed auto snapshot interval stopped after ${state.interval.maxsnapshots} snapshot${state.interval.maxsnapshots === 1 ? "" : "s"}; the retention window of ${state.interval.expiry} millisecond${state.interval.expiry === 1 ? "" : "s"} expires them by user choice.`, { sessionid: session.id, planid: plan.id });
24022
25653
  return;
24023
25654
  }
24024
- const options = stepoptions3(step);
25655
+ const options = stepoptions6(step);
24025
25656
  const snapshot2 = snapshotplanof(options.snapshot);
24026
25657
  if (!snapshot2) return;
24027
25658
  const record2 = await capturesessionrecord({ ...snapshot2, ...snapshot2.auto !== void 0 ? { auto: snapshot2.auto } : {} }, session, plan.id).catch(() => void 0);
@@ -24066,10 +25697,22 @@ async function restoreemulationstate() {
24066
25697
  restoreemulationstate().catch(() => {
24067
25698
  });
24068
25699
  chrome.runtime.onConnect.addListener((port) => {
24069
- if (port.name !== "devthinksidepanel" || port.sender?.id !== chrome.runtime.id || !port.sender.url?.startsWith(chrome.runtime.getURL(""))) return port.disconnect();
24070
- port.onMessage.addListener((message) => {
24071
- handlerequest(message, port.sender ?? {}).then((value) => port.postMessage({ ok: true, value })).catch((error) => port.postMessage({ ok: false, error: error instanceof Error ? error.message : String(error) }));
24072
- });
25700
+ void (async () => {
25701
+ const handshake = portaccept({ portname: port.name, ...port.sender?.id !== void 0 ? { senderid: port.sender.id } : {}, ...port.sender?.origin !== void 0 ? { senderorigin: port.sender.origin } : {}, extensionid: chrome.runtime.id, connectallow: await memory.getconnectallow() });
25702
+ if (!handshake.accepted) {
25703
+ await audit("inbound", `The port ${port.name} closed at its handshake: ${handshake.reason}`, {}).catch(() => {
25704
+ });
25705
+ port.disconnect();
25706
+ return;
25707
+ }
25708
+ if (port.name !== "devthinksidepanel" || port.sender?.id !== chrome.runtime.id || !port.sender.url?.startsWith(chrome.runtime.getURL(""))) {
25709
+ port.disconnect();
25710
+ return;
25711
+ }
25712
+ port.onMessage.addListener((message) => {
25713
+ handlerequest(message, port.sender ?? {}).then((value) => port.postMessage({ ok: true, value })).catch((error) => port.postMessage({ ok: false, error: error instanceof Error ? error.message : String(error) }));
25714
+ });
25715
+ })();
24073
25716
  });
24074
25717
  {
24075
25718
  const webnavigation = chrome.webNavigation;
@@ -24155,4 +25798,16 @@ restoretriggers().catch(() => {
24155
25798
  });
24156
25799
  restorerunstates().catch(() => {
24157
25800
  });
25801
+ async function recordinstalledpermdiff() {
25802
+ const manifest = chrome.runtime.getManifest();
25803
+ const permissions = [...(manifest.permissions ?? []).map((permission) => `required:${permission}`), ...(manifest.optional_permissions ?? []).map((permission) => `optional:${permission}`), ...(manifest.optional_host_permissions ?? []).map((host) => `optionalhost:${host}`)];
25804
+ const last = await memory.getlastpermissions();
25805
+ if (last !== void 0 && last.version === manifest.version) return;
25806
+ const diff = permissiondiff({ from: last?.permissions ?? [], to: permissions, fromversion: last?.version ?? "none", toversion: manifest.version, now: Date.now() });
25807
+ await memory.addpermdiff(diff);
25808
+ await memory.setlastpermissions(permissions, manifest.version);
25809
+ await audit("transparency", `The installed update to ${manifest.version} recorded its permdiff: ${permdiffsummary(diff)}`, {});
25810
+ }
25811
+ recordinstalledpermdiff().catch(() => {
25812
+ });
24158
25813
  //# sourceMappingURL=background.js.map