@wenathlan/extension 1.1.63 → 1.1.65

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 (55) hide show
  1. package/README.md +5 -3
  2. package/dist/datagrid.d.ts +46 -0
  3. package/dist/datagrid.d.ts.map +1 -0
  4. package/dist/evidenceviews.d.ts +45 -0
  5. package/dist/evidenceviews.d.ts.map +1 -0
  6. package/dist/index.d.ts +11 -1
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +1155 -1
  9. package/dist/index.js.map +4 -4
  10. package/dist/memory.d.ts +65 -1
  11. package/dist/memory.d.ts.map +1 -1
  12. package/dist/pickerviews.d.ts +72 -0
  13. package/dist/pickerviews.d.ts.map +1 -0
  14. package/dist/planreview.d.ts +87 -0
  15. package/dist/planreview.d.ts.map +1 -0
  16. package/dist/policy.d.ts +105 -0
  17. package/dist/policy.d.ts.map +1 -1
  18. package/dist/portability.d.ts +35 -0
  19. package/dist/portability.d.ts.map +1 -0
  20. package/dist/protocol.d.ts +248 -0
  21. package/dist/protocol.d.ts.map +1 -1
  22. package/dist/quickactions.d.ts +46 -0
  23. package/dist/quickactions.d.ts.map +1 -0
  24. package/dist/siteprefs.d.ts +45 -0
  25. package/dist/siteprefs.d.ts.map +1 -0
  26. package/dist/statusviews.d.ts +65 -0
  27. package/dist/statusviews.d.ts.map +1 -0
  28. package/dist/surfaces.d.ts +59 -0
  29. package/dist/surfaces.d.ts.map +1 -0
  30. package/dist/tourviews.d.ts +28 -0
  31. package/dist/tourviews.d.ts.map +1 -0
  32. package/dist/types.d.ts +429 -3
  33. package/dist/types.d.ts.map +1 -1
  34. package/dist/version.d.ts +1 -1
  35. package/extension/dist/background.js +1567 -2
  36. package/extension/dist/background.js.map +4 -4
  37. package/extension/dist/dashboardpage.html +14 -0
  38. package/extension/dist/dashboardpage.js +147 -0
  39. package/extension/dist/dashboardpage.js.map +7 -0
  40. package/extension/dist/manifest.json +5 -2
  41. package/extension/dist/offscreen.js +1 -0
  42. package/extension/dist/offscreen.js.map +2 -2
  43. package/extension/dist/optionspage.html +18 -0
  44. package/extension/dist/optionspage.js +267 -0
  45. package/extension/dist/optionspage.js.map +7 -0
  46. package/extension/dist/pagebridge.js.map +1 -1
  47. package/extension/dist/popup.html +4 -1
  48. package/extension/dist/popup.js +257 -0
  49. package/extension/dist/popup.js.map +3 -3
  50. package/extension/dist/sidepanel.html +7 -2
  51. package/extension/dist/sidepanel.js +360 -0
  52. package/extension/dist/sidepanel.js.map +2 -2
  53. package/extension/dist/style.css +3 -1
  54. package/extension/manifest.json +5 -2
  55. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -5206,6 +5206,121 @@ var sessionmemory = class {
5206
5206
  async exportsessionbundle(exportedat) {
5207
5207
  return { kind: "sessionbundle", notes: await this.getsitenotes(), summaries: await this.listrunsummaries(), corrections: await this.getcorrections(), exportedat };
5208
5208
  }
5209
+ /**
5210
+ * Interface surface stores of the 1.1.64 family live here, scoped per profile workspace: the commandpalette usage counts the recent first ranking reads, the taskinput history of natural language goals, the onboarding completion state, the per surface layout preferences, the logstream filter preferences and the stepapprove resolution history per origin.
5211
+ */
5212
+ /** Returns every commandpalette usage record so the ranking lifts the recent commands first. */
5213
+ async getpaletteusage() {
5214
+ return await this.adapter.get("paletteusage") ?? [];
5215
+ }
5216
+ /** Replaces the commandpalette usage records after one use: the count grows and the last use time moves so the ranking reads both. */
5217
+ async setpaletteusage(records) {
5218
+ return this.adapter.set("paletteusage", records);
5219
+ }
5220
+ /** Returns the stored taskinput history, newest first. */
5221
+ async gettaskinputs() {
5222
+ return await this.adapter.get("taskinputs") ?? [];
5223
+ }
5224
+ /** Adds one taskinput submission to the per profile history; the retention window stays a user setting. */
5225
+ async addtaskinput(entry) {
5226
+ const retention = (await this.getsettings())?.taskinputretention;
5227
+ const history = [entry, ...await this.gettaskinputs()];
5228
+ await this.adapter.set("taskinputs", retention === void 0 ? history : history.filter((candidate) => entry.at - candidate.at < retention));
5229
+ }
5230
+ /** Returns the onboarding completion state; an absent state means the walkthrough never ran. */
5231
+ async getonboardingstate() {
5232
+ return this.adapter.get("onboarding");
5233
+ }
5234
+ /** Stores the onboarding completion state; a done walkthrough never runs again on its own. */
5235
+ async setonboardingstate(state) {
5236
+ return this.adapter.set("onboarding", state);
5237
+ }
5238
+ /** Returns the layout preferences of one surface; an absent preference set returns undefined. */
5239
+ async getsurfacelayout(surface) {
5240
+ return this.adapter.get(`surfacelayout:${surface}`);
5241
+ }
5242
+ /** Stores the layout preferences of one surface, scoped per profile workspace. */
5243
+ async setsurfacelayout(layout) {
5244
+ return this.adapter.set(`surfacelayout:${layout.surface}`, layout);
5245
+ }
5246
+ /** Returns the stored logstream filter preferences of the live view. */
5247
+ async getlogstreamfilters() {
5248
+ return this.adapter.get("logstreamfilters");
5249
+ }
5250
+ /** Stores the logstream filter preferences of the live view. */
5251
+ async setlogstreamfilters(filter) {
5252
+ return this.adapter.set("logstreamfilters", filter);
5253
+ }
5254
+ /** Returns every stored stepapprove resolution, newest first, with its human provenance. */
5255
+ async getstepapproveresolutions() {
5256
+ return await this.adapter.get("stepapproveresolutions") ?? [];
5257
+ }
5258
+ /** Records one stepapprove resolution in the per origin history. */
5259
+ async addstepapproveresolution(resolution) {
5260
+ await this.adapter.set("stepapproveresolutions", [resolution, ...await this.getstepapproveresolutions()]);
5261
+ }
5262
+ /**
5263
+ * Interface surface stores of the 1.1.65 family live here, scoped per profile workspace: the siteprofiles with the per site interface preferences, the shortcutkeys bindings and the theme preference per profile, the recenttray entries with their configurable depth and the notification consent and preference per profile.
5264
+ */
5265
+ /** Returns the siteprofile of one origin; an absent profile keeps the global interface preferences. */
5266
+ async getsiteprofile(origin) {
5267
+ return this.adapter.get(`siteprofile:${origin}`);
5268
+ }
5269
+ /** Stores the siteprofile of one origin with its theme, shortcutkeys and default view; the profile never adjusts a policy gate. */
5270
+ async setsiteprofile(profile) {
5271
+ return this.adapter.set(`siteprofile:${profile.origin}`, profile);
5272
+ }
5273
+ /** Returns every stored siteprofile keyed by origin. */
5274
+ async listsiteprofiles() {
5275
+ const entries = Object.entries(await this.adapter.get("siteprofiles") ?? {});
5276
+ return entries.map(([, profile]) => profile);
5277
+ }
5278
+ /** Stores every siteprofile keyed by origin so the list view reads them in one call. */
5279
+ async setsiteprofiles(profiles) {
5280
+ await this.adapter.set("siteprofiles", Object.fromEntries(profiles.map((profile) => [profile.origin, profile])));
5281
+ }
5282
+ /** Returns the stored shortcutkeys bindings of the profile; an absent set keeps the shipped editable defaults. */
5283
+ async getshortcutbindings() {
5284
+ return await this.adapter.get("shortcutbindings") ?? [];
5285
+ }
5286
+ /** Stores the shortcutkeys bindings the user edited in the optionspage. */
5287
+ async setshortcutbindings(bindings) {
5288
+ return this.adapter.set("shortcutbindings", bindings);
5289
+ }
5290
+ /** Returns the stored darklight theme preference of the profile; an absent preference follows the os preference alone. */
5291
+ async getthemepreference() {
5292
+ return this.adapter.get("themepreference");
5293
+ }
5294
+ /** Stores the darklight theme preference of the profile with its manual override. */
5295
+ async setthemepreference(preference) {
5296
+ return this.adapter.set("themepreference", preference);
5297
+ }
5298
+ /** Returns the recenttray entries, newest first, with their resume and reopen offers. */
5299
+ async getrecenttray() {
5300
+ return await this.adapter.get("recenttray") ?? [];
5301
+ }
5302
+ /** Adds one recenttray entry with the user configured depth; an absent depth keeps every run. */
5303
+ async addrecenttrayentry(entry) {
5304
+ const depth = (await this.getsettings())?.recenttraydepth;
5305
+ const appended = [entry, ...(await this.getrecenttray()).filter((candidate) => candidate.runid !== entry.runid)];
5306
+ await this.adapter.set("recenttray", depth !== void 0 && Number.isInteger(depth) && depth > 0 ? appended.slice(0, depth) : appended);
5307
+ }
5308
+ /** Returns the notification consent and preference of the profile; an absent record keeps the notifications content free and on. */
5309
+ async getnotificationprefs() {
5310
+ return this.adapter.get("notificationprefs");
5311
+ }
5312
+ /** Stores the notification consent and preference of the profile; the content consent gates every page content bearing body. */
5313
+ async setnotificationprefs(prefs) {
5314
+ return this.adapter.set("notificationprefs", prefs);
5315
+ }
5316
+ /** Returns the notification payloads the surface history keeps for the user to open after a do not disturb quiet. */
5317
+ async getnotificationhistory() {
5318
+ return await this.adapter.get("notificationhistory") ?? [];
5319
+ }
5320
+ /** Records one notification payload in the history so its deep link stays reachable while the notifications permission stays outside the manifest. */
5321
+ async addnotificationhistory(payload) {
5322
+ await this.adapter.set("notificationhistory", [payload, ...await this.getnotificationhistory()]);
5323
+ }
5209
5324
  };
5210
5325
  function mediakindof(record2) {
5211
5326
  if ("pages" in record2) return "pdf";
@@ -11350,6 +11465,93 @@ function retrydispatchgate(input) {
11350
11465
  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.` };
11351
11466
  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.` };
11352
11467
  }
11468
+ function paletteactiongate(input) {
11469
+ if (input.action.permission !== void 0 && !input.granted.includes(input.action.permission)) return { allowed: false, reason: `The ${input.action.command} command needs the ${input.action.permission} capability granted before the palette lists it; the palette never offers an action the current capability set refuses.` };
11470
+ if (input.action.session === true && !input.sessionactive) return { allowed: false, reason: `The ${input.action.command} command needs an active browser session before the palette lists it; the palette never offers a run action without its session.` };
11471
+ return { allowed: true, reason: `The ${input.action.command} command rides its granted permissions and lists in the palette.` };
11472
+ }
11473
+ function taskinputproposalgate(input) {
11474
+ if (input.direct) return { allowed: false, reason: "The taskinput never executes a goal directly; every natural language goal routes through the same proposal flow as the api and becomes a reviewed plan first." };
11475
+ if (input.text.trim() === "") return { allowed: false, reason: "The taskinput submission needs its natural language goal; an empty goal never reaches the proposal flow." };
11476
+ if (input.origin.trim() === "") return { allowed: false, reason: "The taskinput submission needs its active origin scope; a goal without an origin never reaches the proposal flow." };
11477
+ return { allowed: true, reason: `The taskinput goal for ${input.origin} rides the same proposal flow as the api: the observation, the capabilities and the plan review all recheck it.` };
11478
+ }
11479
+ function planreviewgate(input) {
11480
+ if (input.state === "approved") return { allowed: true, reason: "The plan already passed its review: the approval is the review of record and the execution proceeds." };
11481
+ if (!input.reviewed) return { allowed: false, reason: "The pending plan has no plancard review yet; every step renders its card with the risk class, the environment and the options before any execution." };
11482
+ return { allowed: true, reason: "The plancard review of the pending plan is open; the resolution of each step stays a distinct human action." };
11483
+ }
11484
+ function stepapprovegate(input) {
11485
+ if (input.stepids.length === 0) return { allowed: false, reason: "A stepapprove resolution names its single step." };
11486
+ if (input.stepids.length > 1) return { allowed: false, reason: `One human action resolves exactly one step; the batch of ${input.stepids.length} steps refuses in full because no batch approval exists.` };
11487
+ if (input.surface === "background") return { allowed: false, reason: `The ${input.resolution} resolution of the step ${input.stepids[0]} needs its distinct human action from a surface; the background never resolves a review on its own.` };
11488
+ if (input.resolution === "edit") return { allowed: true, reason: `The user edits the step ${input.stepids[0]} from the ${input.surface} before approving; the corrected shape rides the plan and the resolution keeps its human provenance.` };
11489
+ return { allowed: true, reason: `The user ${input.resolution === "approve" ? "approved" : "rejected"} the step ${input.stepids[0]} from the ${input.surface}; one distinct human action resolved the step alone.` };
11490
+ }
11491
+ function diffpreviewgate(input) {
11492
+ if (input.risk !== "sensitive") return { allowed: false, reason: `The ${input.risk} step changes no page or browser state; the diffpreview compares the observed before state with the predicted after state of write class steps only.` };
11493
+ return { allowed: true, reason: "The write class step changes page or browser state, so the diffpreview compares its observed before state with its predicted after state." };
11494
+ }
11495
+ function onboardingconsentgate(input) {
11496
+ if (input.consentevents.length === 0) return { allowed: true, reason: "The onboarding completion writes its single consent scoped event; no consent event exists yet." };
11497
+ if (input.consentevents.length === 1) return { allowed: false, reason: `The onboarding already wrote its single consent scoped event ${input.consentevents[0]}; a walkthrough never writes a second one.` };
11498
+ return { allowed: false, reason: `The onboarding found ${input.consentevents.length} consent scoped events; a walkthrough writes exactly one and the extra events refuse.` };
11499
+ }
11500
+ function logbufferboundvalid(bound) {
11501
+ if (bound === void 0) return { allowed: true, reason: "No logstream buffer bound is configured, so the live window keeps every event while the full history stays in memory." };
11502
+ if (!Number.isInteger(bound) || bound <= 0) return { allowed: false, reason: "The logstream buffer bound stays a positive whole number of events the user chose; no engine cap exists." };
11503
+ return { allowed: true, reason: `The logstream buffer bound of ${bound} event${bound === 1 ? "" : "s"} stays the user configured choice; the full history stays in memory.` };
11504
+ }
11505
+ function logstreamegressgate(input) {
11506
+ if (input.entries === 0) return { allowed: false, reason: "The audit excerpt names no event of the logstream; an empty range never copies." };
11507
+ if (!input.verified) return { allowed: false, reason: "The logstream chain failed its live verification; the audit excerpt refuses the copy because only a verified range leaves the stream." };
11508
+ return { allowed: true, reason: `The logstream chain verifies across the ${input.entries} event${input.entries === 1 ? "" : "s"} of the range; the audit excerpt copies as one verified record.` };
11509
+ }
11510
+ function quickactiongate(input) {
11511
+ if (input.action.origin.trim() === "") return { allowed: false, reason: `The ${input.action.command} quickaction needs the origin of the clicked tab; an originless entry never registers.` };
11512
+ if (!input.granted.includes(input.action.origin)) return { allowed: false, reason: `The ${input.action.command} quickaction stays off the ${input.action.origin} tab because its origin holds no allowlist entry; only permitted actions surface.` };
11513
+ if (input.action.session === true && !input.sessionactive) return { allowed: false, reason: `The ${input.action.command} quickaction needs an active browser session before it registers; the context menu never offers a run action without its session.` };
11514
+ if (input.action.permission !== void 0 && !(input.capabilities ?? []).includes(input.action.permission)) return { allowed: false, reason: `The ${input.action.command} quickaction needs the ${input.action.permission} capability granted before it registers; the context menu never offers an action the current capability set refuses.` };
11515
+ return { allowed: true, reason: `The ${input.action.command} quickaction rides the origin allowlist of the clicked ${input.action.origin} tab and registers.` };
11516
+ }
11517
+ function omniboxtaskgate(input) {
11518
+ if (input.direct) return { allowed: false, reason: "The omnibox keyword never executes a goal directly; every keyword goal routes through the same proposal and review flow as the api and becomes a reviewed plan first." };
11519
+ if (input.text.trim() === "") return { allowed: false, reason: "The omnibox task needs its natural language goal after the keyword; an empty goal never reaches the proposal flow." };
11520
+ if (input.origin.trim() === "") return { allowed: false, reason: "The omnibox task needs its active origin scope; a goal without an origin never reaches the proposal flow." };
11521
+ return { allowed: true, reason: `The omnibox goal for ${input.origin} rides the same proposal flow as the api: the observation, the capabilities and the plan review all recheck it.` };
11522
+ }
11523
+ function shortcutkeygate(input) {
11524
+ if (!input.palettecommands.includes(input.command)) return { allowed: false, reason: `The ${input.command} shortcut binds no commandpalette command; a shortcut may only trigger a command the palette catalog knows.` };
11525
+ if (input.action?.permission !== void 0 && !input.granted.includes(input.action.permission)) return { allowed: false, reason: `The ${input.command} shortcut needs the ${input.action.permission} capability granted before it dispatches; the shortcut never bypasses the palette action gate.` };
11526
+ if (input.action?.session === true && !input.sessionactive) return { allowed: false, reason: `The ${input.command} shortcut needs an active browser session before it dispatches; the shortcut never bypasses the palette action gate.` };
11527
+ return { allowed: true, reason: `The ${input.command} shortcut dispatches through the same palette action gate the commandpalette rides; its gates stay intact.` };
11528
+ }
11529
+ function notificationcontentgate(input) {
11530
+ if (!input.content) return { allowed: true, reason: "The notification body carries no page content, so no content consent is needed and it shows." };
11531
+ if (!input.consent) return { allowed: false, reason: "The notification body carries page content and no content consent exists; a content bearing notification never shows without its consent." };
11532
+ return { allowed: true, reason: "The notification body carries page content and its consent exists, so it shows with the content the user agreed to." };
11533
+ }
11534
+ function pickeroverlaygate(input) {
11535
+ if (input.origin.trim() === "") return { allowed: false, reason: "The pickeroverlay session needs its origin; an originless read never starts." };
11536
+ if (!input.granted.includes(input.origin)) return { allowed: false, reason: `The pickeroverlay reads no element candidate of ${input.origin} because the origin holds no allowlist entry; picker reads stay inside the granted origins.` };
11537
+ return { allowed: true, reason: `The pickeroverlay lists the element candidates of the granted origin ${input.origin} with their stability scored selectors.` };
11538
+ }
11539
+ function shotpanelgate(input) {
11540
+ if (input.captureorigin.trim() === "") return { allowed: false, reason: "The shotpanel view needs the origin of its capture; an originless capture never opens." };
11541
+ if (!input.granted.includes(input.captureorigin)) return { allowed: false, reason: `The shotpanel opens no capture of ${input.captureorigin} because the origin holds no allowlist entry; capture views stay inside the granted origins.` };
11542
+ return { allowed: true, reason: `The shotpanel previews the capture of the granted origin ${input.captureorigin} with its redaction verdicts.` };
11543
+ }
11544
+ function siteprofilegate(input) {
11545
+ const origin = input.origin.trim();
11546
+ if (origin === "") return { allowed: false, reason: "The siteprofile needs its origin; an originless profile never stores." };
11547
+ if (!origin.startsWith("https://") || origin.length <= "https://".length) return { allowed: false, reason: `The siteprofile stores per site interface preferences of https origins only; ${origin} holds no https origin shape.` };
11548
+ return { allowed: true, reason: `The siteprofile of ${origin} stores its theme, shortcutkeys and default view beside the originprofiles policy preferences; no profile ever adjusts a policy gate.` };
11549
+ }
11550
+ function importexportgate(input) {
11551
+ if (input.containssecrets) return { allowed: false, reason: "The importexport bundle carries a secretvault value shape; secret values never leave the browser under any flag, so the bundle refuses in full." };
11552
+ if (input.unmaskedlogs) return { allowed: false, reason: "The importexport bundle carries unmasked log entries; only masked summaries ever move between profiles, so the bundle refuses in full." };
11553
+ return { allowed: true, reason: "The importexport bundle carries no secretvault value and no unmasked log; the originprofiles, the siteprofiles, the notes and the preferences move with their honest exclusion list." };
11554
+ }
11353
11555
 
11354
11556
  // llm.ts
11355
11557
  var defaultrefusalmarkers = ["i cannot", "i can't", "i'm unable", "refusal:", "cannot comply"];
@@ -11710,7 +11912,7 @@ function budgetcheck(input) {
11710
11912
  }
11711
11913
 
11712
11914
  // version.ts
11713
- var packageversion = "1.1.63";
11915
+ var packageversion = "1.1.65";
11714
11916
 
11715
11917
  // types.ts
11716
11918
  var protocolversion = packageversion;
@@ -13056,6 +13258,833 @@ function sessionbundleof(input) {
13056
13258
  return { kind: "sessionbundle", notes: input.notes, summaries: input.summaries, corrections: input.corrections, exportedat: input.exportedat };
13057
13259
  }
13058
13260
 
13261
+ // planreview.ts
13262
+ function plancardsof(input) {
13263
+ return input.plan.steps.map((step) => ({
13264
+ stepid: step.id,
13265
+ kind: step.kind,
13266
+ risk: step.risk,
13267
+ environment: step.environment ?? defaultenvironment(step),
13268
+ options: step.options ?? "",
13269
+ summary: step.summary,
13270
+ corrections: matchingcorrections(input.corrections, { origin: input.plan.origin, kind: step.kind }).map((entry) => ({ id: entry.id, source: entry.source, reason: entry.reason })),
13271
+ editable: input.plan.state === "pending"
13272
+ }));
13273
+ }
13274
+ function plancardgroups(cards) {
13275
+ const order = ["sensitive", "interaction", "read"];
13276
+ return order.map((risk) => ({ risk, cards: cards.filter((card) => card.risk === risk), expanded: risk === "sensitive" })).filter((group) => group.cards.length > 0);
13277
+ }
13278
+ function stepresolutionof(input) {
13279
+ if (input.stepid.trim() === "") throw new Error("The stepapprove resolution needs its step.");
13280
+ if (input.resolution === "edit" && (input.edited ?? "").trim() === "") throw new Error("The edited resolution needs its corrected step shape.");
13281
+ return { stepid: input.stepid, planid: input.planid, origin: input.origin, resolution: input.resolution, surface: input.surface, ...input.edited !== void 0 && input.edited.trim() !== "" ? { edited: input.edited } : {}, at: input.at };
13282
+ }
13283
+ function resolutionlogeventof(resolution) {
13284
+ return {
13285
+ kind: "review",
13286
+ stepid: resolution.stepid,
13287
+ summary: resolution.resolution === "edit" ? `The user edited the step ${resolution.stepid} of the plan ${resolution.planid} from the ${resolution.surface} before approving; the corrected shape rides the plan.` : `The user ${resolution.resolution === "approve" ? "approved" : "rejected"} the step ${resolution.stepid} of the plan ${resolution.planid} from the ${resolution.surface}; one distinct human action resolved the step alone.`
13288
+ };
13289
+ }
13290
+ function resolutionhistoryafter(history, resolution) {
13291
+ return [resolution, ...history];
13292
+ }
13293
+ function maskverdictsof(state, sensitivefields) {
13294
+ const verdicts = {};
13295
+ for (const [field, value] of Object.entries(state)) {
13296
+ if (sensitivefields.includes(field)) verdicts[field] = `The ${field} value stays masked (${value.length} characters) and never renders in the clear.`;
13297
+ }
13298
+ return verdicts;
13299
+ }
13300
+ function diffpreviewof(input) {
13301
+ const changes = [];
13302
+ const fields = [.../* @__PURE__ */ new Set([...Object.keys(input.before), ...Object.keys(input.after)])];
13303
+ for (const field of fields) {
13304
+ const hasbefore = Object.prototype.hasOwnProperty.call(input.before, field);
13305
+ const hasafter = Object.prototype.hasOwnProperty.call(input.after, field);
13306
+ const beforevalue = input.before[field];
13307
+ const aftervalue = input.after[field];
13308
+ if (hasbefore && !hasafter && beforevalue !== void 0) changes.push({ field, kind: "removed", before: beforevalue });
13309
+ else if (!hasbefore && hasafter && aftervalue !== void 0) changes.push({ field, kind: "added", after: aftervalue });
13310
+ else if (hasbefore && hasafter && beforevalue !== void 0 && aftervalue !== void 0 && beforevalue !== aftervalue) changes.push({ field, kind: "changed", before: beforevalue, after: aftervalue });
13311
+ }
13312
+ return { stepid: input.stepid, before: input.before, after: input.after, changes, maskverdicts: input.maskverdicts ?? {}, provenance: input.provenance };
13313
+ }
13314
+ function stepstimelinenodes(input) {
13315
+ const completed = input.progress?.completedsteps ?? [];
13316
+ const outcomes = input.progress?.outcomes ?? [];
13317
+ const environments = input.progress?.environments;
13318
+ const turnarounds = input.progress?.turnarounds;
13319
+ const gatewaits = input.progress?.gatewaits;
13320
+ let activeset = false;
13321
+ let blocked = false;
13322
+ return input.plan.steps.map((step) => {
13323
+ const outcome = [...outcomes].reverse().find((candidate) => candidate.stepid === step.id);
13324
+ const gatewait = gatewaits?.[step.id];
13325
+ let status;
13326
+ if (outcome !== void 0) status = outcome.ok ? "done" : "failed";
13327
+ else if (gatewait !== void 0) status = "waiting";
13328
+ else if (completed.includes(step.id)) status = "done";
13329
+ else if (input.plan.state === "cancelled" || input.plan.state === "expired") status = "halted";
13330
+ else if (input.plan.state === "rejected") status = "halted";
13331
+ else if (input.plan.state === "approved" && !activeset && !blocked) {
13332
+ status = "running";
13333
+ activeset = true;
13334
+ } else status = "pending";
13335
+ if (status === "waiting") blocked = true;
13336
+ const active = status === "running";
13337
+ return {
13338
+ stepid: step.id,
13339
+ kind: step.kind,
13340
+ status,
13341
+ ...turnarounds?.[step.id] !== void 0 ? { durationms: turnarounds[step.id] } : {},
13342
+ ...environments?.[step.id] !== void 0 ? { environment: environments[step.id] } : step.environment !== void 0 ? { environment: step.environment } : {},
13343
+ active,
13344
+ anchor: `#step-${step.id}`,
13345
+ ...outcome !== void 0 ? { resultsummary: outcome.summary } : {}
13346
+ };
13347
+ });
13348
+ }
13349
+ function activetimelineanchor(nodes) {
13350
+ return nodes.find((node) => node.active)?.anchor;
13351
+ }
13352
+ var logstreamgenesis = "0".repeat(64);
13353
+ async function logstreameventof(input) {
13354
+ if (input.summary.trim() === "") throw new Error("The logstream event needs its summary.");
13355
+ const id = randomid();
13356
+ const hash = await entryhashof({ previous: input.previous, entry: { id, runid: "surfaces", kind: "step", summary: input.summary, origin: input.origin, ...input.stepid !== void 0 ? { stepid: input.stepid } : {}, at: input.at } });
13357
+ return { id, level: input.level, source: input.source, origin: input.origin, summary: input.summary, ...input.stepid !== void 0 ? { stepid: input.stepid } : {}, masked: input.masked, maskverdict: input.maskverdict, hash, at: input.at };
13358
+ }
13359
+ function appendlogstreamevent(events, event) {
13360
+ return [...events, event];
13361
+ }
13362
+ function filterlogstream(events, filter) {
13363
+ return events.filter((event) => (filter.level === void 0 || event.level === filter.level) && (filter.origin === void 0 || filter.origin === "" || event.origin === filter.origin) && (filter.stepid === void 0 || filter.stepid === "" || event.stepid === filter.stepid));
13364
+ }
13365
+ function livebufferof(events, bound) {
13366
+ if (bound === void 0) return events;
13367
+ if (!Number.isInteger(bound) || bound <= 0) return events;
13368
+ return events.slice(-bound);
13369
+ }
13370
+ async function verifylogstream(events) {
13371
+ for (let index = 0; index < events.length; index += 1) {
13372
+ const event = events[index];
13373
+ if (event === void 0) continue;
13374
+ const predecessor = events[index - 1];
13375
+ const expectedprevious = index === 0 || predecessor === void 0 ? logstreamgenesis : predecessor.hash.current;
13376
+ if (event.hash.previous !== expectedprevious) return { valid: false, brokenat: index, reason: `The logstream chain breaks at the event ${event.id}: its previous hash does not link to its predecessor.` };
13377
+ const recomputed = await entryhashof({ previous: event.hash.previous, entry: { id: event.id, runid: "surfaces", kind: "step", summary: event.summary, origin: event.origin, ...event.stepid !== void 0 ? { stepid: event.stepid } : {}, at: event.at } });
13378
+ if (recomputed.current !== event.hash.current) return { valid: false, brokenat: index, reason: `The logstream chain breaks at the event ${event.id}: its own hash does not reproduce.` };
13379
+ }
13380
+ return { valid: true, reason: `The logstream chain of ${events.length} event${events.length === 1 ? "" : "s"} verifies link by link.` };
13381
+ }
13382
+ async function auditexcerptof(events, input) {
13383
+ if (input.from < 0 || input.to <= input.from || input.to > events.length) return { ok: false, text: "", reason: `The excerpt range ${input.from} to ${input.to} names no contiguous slice of the ${events.length} event${events.length === 1 ? "" : "s"}.` };
13384
+ const range = events.slice(input.from, input.to);
13385
+ const verification = await verifylogstream(range);
13386
+ if (!verification.valid) return { ok: false, text: "", reason: `The excerpt refuses the copy: ${verification.reason}` };
13387
+ const text2 = range.map((event) => `[${event.at}] ${event.level} ${event.source}${event.stepid !== void 0 ? ` step ${event.stepid}` : ""} ${event.origin} \u2014 ${event.summary}${event.masked ? ` (${event.maskverdict})` : ""}`).join("\n");
13388
+ return { ok: true, text: text2, reason: `The excerpt copied the verified range ${input.from} to ${input.to} of the logstream.` };
13389
+ }
13390
+ function loglevelof(kind) {
13391
+ if (kind === "error") return "error";
13392
+ if (["deny", "revoke", "stop", "quarantine", "phish", "defer", "schema", "expiry"].includes(kind)) return "warn";
13393
+ return "info";
13394
+ }
13395
+
13396
+ // surfaces.ts
13397
+ function surfacepalette() {
13398
+ return [
13399
+ { id: "starttask", label: "Start task", keywords: ["task", "objective", "run", "goal", "plan"], action: { command: "starttask", surface: "popup" } },
13400
+ { id: "pauserun", label: "Pause run", keywords: ["pause", "hold", "stop", "run"], action: { command: "pauserun", surface: "popup", session: true } },
13401
+ { id: "resumerun", label: "Resume run", keywords: ["resume", "continue", "unpause", "run"], action: { command: "resumerun", surface: "popup", session: true } },
13402
+ { id: "cancelrun", label: "Cancel run", keywords: ["cancel", "stop", "rollback", "queued"], action: { command: "cancelrun", surface: "popup", session: true } },
13403
+ { id: "resumesession", label: "Resume session", keywords: ["session", "resume", "grid", "reopen"], action: { command: "resumesession", surface: "sidepanel" } },
13404
+ { id: "stepapprove", label: "Review step", keywords: ["approve", "reject", "edit", "step", "review", "plancard"], action: { command: "stepapprove", surface: "sidepanel", session: true } },
13405
+ { id: "diffpreview", label: "Preview step diff", keywords: ["diff", "preview", "before", "after", "write"], action: { command: "diffpreview", surface: "sidepanel", session: true } },
13406
+ { id: "historysearch", label: "Search history", keywords: ["history", "search", "notes", "summaries", "corpus"], action: { command: "historysearch", surface: "dashboardpage" } },
13407
+ { id: "revokeconsent", label: "Revoke consent", keywords: ["revoke", "consent", "allowlist", "origin", "grant"], action: { command: "revokeconsent", surface: "dashboardpage", session: true } },
13408
+ { id: "opentransparencypage", label: "Open transparency page", keywords: ["transparency", "grants", "permissions", "diff"], action: { command: "opentransparencypage", surface: "optionspage" } },
13409
+ { id: "opendashboardpage", label: "Open dashboard", keywords: ["dashboard", "sessions", "runs", "notes", "full"], action: { command: "opendashboardpage", surface: "dashboardpage" } },
13410
+ { id: "openoptionspage", label: "Open options", keywords: ["options", "settings", "preferences", "configure"], action: { command: "openoptionspage", surface: "optionspage" } },
13411
+ { id: "copyauditexcerpt", label: "Copy audit excerpt", keywords: ["audit", "excerpt", "copy", "verified", "range"], action: { command: "copyauditexcerpt", surface: "dashboardpage" } },
13412
+ { id: "replayonboarding", label: "Replay onboarding", keywords: ["onboarding", "tour", "walkthrough", "replay", "first"], action: { command: "replayonboarding", surface: "onboarding" } }
13413
+ ];
13414
+ }
13415
+ function palettecommandsof(entries, input) {
13416
+ return entries.filter((entry) => paletteactiongate({ action: entry.action, granted: input.granted, sessionactive: input.sessionactive }).allowed);
13417
+ }
13418
+ function fuzzyentryscore(entry, query) {
13419
+ const text2 = query.trim().toLowerCase();
13420
+ if (text2 === "") return 1;
13421
+ const id = entry.id.toLowerCase();
13422
+ const label = entry.label.toLowerCase();
13423
+ if (id === text2 || label === text2) return 100;
13424
+ let score = 0;
13425
+ if (id.includes(text2)) score += 40;
13426
+ if (label.includes(text2)) score += 30;
13427
+ for (const keyword of entry.keywords) {
13428
+ const lower = keyword.toLowerCase();
13429
+ if (lower === text2) score += 20;
13430
+ else if (lower.includes(text2)) score += 10;
13431
+ }
13432
+ if (score === 0 && text2.length > 1) {
13433
+ for (const haystack of [label, id]) {
13434
+ let cursor = 0;
13435
+ let matched = true;
13436
+ for (const letter of text2) {
13437
+ const found = haystack.indexOf(letter, cursor);
13438
+ if (found === -1) {
13439
+ matched = false;
13440
+ break;
13441
+ }
13442
+ cursor = found + 1;
13443
+ }
13444
+ if (matched) {
13445
+ score += 15;
13446
+ break;
13447
+ }
13448
+ }
13449
+ }
13450
+ return score;
13451
+ }
13452
+ function palettequery(entries, input) {
13453
+ const text2 = input.text.trim();
13454
+ const matches = entries.map((entry) => ({ entry, score: fuzzyentryscore(entry, text2) })).filter((match) => match.score > 0);
13455
+ const lastusedof = (command) => input.usage.find((record2) => record2.command === command)?.lastusedat ?? 0;
13456
+ const countof = (command) => input.usage.find((record2) => record2.command === command)?.count ?? 0;
13457
+ const recentwindow = input.recentwindow;
13458
+ const ranked = matches.sort((left, right) => {
13459
+ if (right.score !== left.score) return right.score - left.score;
13460
+ const leftrecent = recentwindow === void 0 ? 0 : countof(left.entry.action.command) > 0 && lastusedof(left.entry.action.command) >= lastusedof(right.entry.action.command) ? 1 : 0;
13461
+ const rightrecent = recentwindow === void 0 ? 0 : countof(right.entry.action.command) > 0 && lastusedof(right.entry.action.command) >= lastusedof(left.entry.action.command) ? 1 : 0;
13462
+ if (rightrecent !== leftrecent) return rightrecent - leftrecent;
13463
+ return lastusedof(right.entry.action.command) - lastusedof(left.entry.action.command);
13464
+ });
13465
+ return ranked.map((match) => ({ entry: match.entry, score: match.score, reason: match.score >= 100 ? `The query matches the ${match.entry.id} command exactly.` : `The query matches the label or the keywords of the ${match.entry.id} command${countof(match.entry.action.command) > 0 ? ` and its ${countof(match.entry.action.command)} recorded use${countof(match.entry.action.command) === 1 ? "" : "s"} rank it first among equals` : ""}.` }));
13466
+ }
13467
+ function paletteuseafter(usage, command, now) {
13468
+ const existing = usage.find((record2) => record2.command === command);
13469
+ if (existing === void 0) return [{ command, count: 1, lastusedat: now }, ...usage];
13470
+ return usage.map((record2) => record2.command === command ? { ...record2, count: record2.count + 1, lastusedat: now } : record2);
13471
+ }
13472
+ function taskinputof(input) {
13473
+ if (input.text.trim() === "") throw new Error("The taskinput needs its natural language goal.");
13474
+ if (input.origin.trim() === "") throw new Error("The taskinput needs its active origin scope.");
13475
+ return { id: randomid(), text: input.text.trim(), context: input.context ?? "", origin: input.origin.trim(), surface: input.surface, at: input.at };
13476
+ }
13477
+ function taskhistoryafter(history, entry, retention, now) {
13478
+ if (retention === void 0) return [entry, ...history];
13479
+ return [entry, ...history].filter((candidate) => now - candidate.at < retention);
13480
+ }
13481
+ function onboardingsteps() {
13482
+ return [
13483
+ { id: "origingrants", surface: "popup", title: "Origin grants", body: "Devthink denies automation by default; grant one exact origin at a time from the popup and every run stays inside the granted origins.", completion: "origingrantscompleted" },
13484
+ { id: "planreview", surface: "sidepanel", title: "Plan review", body: "Every task becomes a plan of reviewed steps; read the plancards of each risk class and approve, reject or edit one step at a time.", completion: "planreviewcompleted" },
13485
+ { id: "runcontrol", surface: "sidepanel", title: "Run control", body: "Runs start, pause, resume and cancel under your hand; a cancelled run rolls only its queued steps back while the executed steps stay sealed.", completion: "runcontrolcompleted" },
13486
+ { id: "logaudit", surface: "dashboardpage", title: "Log audit", body: "The immutable log chains every step transition with masked values; open the dashboard, verify the chain and copy a verified range as an audit excerpt.", completion: "logauditcompleted" }
13487
+ ];
13488
+ }
13489
+ function onboardingstart(previous, now) {
13490
+ return { stepscompleted: [], done: false, startedat: now };
13491
+ }
13492
+ function onboardingcomplete(state, stepid, now) {
13493
+ const steps = onboardingsteps();
13494
+ const step = steps.find((candidate) => candidate.id === stepid);
13495
+ if (step === void 0) throw new Error(`The onboarding knows no ${stepid} step.`);
13496
+ const completed = state.stepscompleted.includes(stepid) ? state.stepscompleted : [...state.stepscompleted, stepid];
13497
+ const done = steps.every((candidate) => completed.includes(candidate.id));
13498
+ if (!done) return { state: { ...state, stepscompleted: completed, done: false } };
13499
+ const consentevent = "onboardingconsentgranted";
13500
+ return { state: { stepscompleted: completed, done: true, ...state.startedat !== void 0 ? { startedat: state.startedat } : {}, consentevent, completedat: now }, consentevent };
13501
+ }
13502
+ function broadcastframeof(input) {
13503
+ if (input.summary.trim() === "") throw new Error("The broadcast frame needs its summary.");
13504
+ return { channel: input.channel, surface: input.surface, summary: input.summary, at: input.at };
13505
+ }
13506
+ function broadcastchannelof(kind) {
13507
+ if (["session", "proposal", "approval", "action", "stop", "pause", "resume", "complete", "cancel", "error", "capability"].includes(kind)) return "runstate";
13508
+ if (["notes", "scratchpad", "summary", "recall", "correction", "consentmemory", "search", "vault", "gate", "grant", "revoke", "expiry", "deny"].includes(kind)) return "sessions";
13509
+ if (["configure", "transparency"].includes(kind)) return "settings";
13510
+ return "logstream";
13511
+ }
13512
+ function busrouteaction(action, input) {
13513
+ const entry = surfacepalette().find((candidate) => candidate.action.command === action.command);
13514
+ if (entry === void 0) return { dispatched: false, gate: "commandbus", reason: `The ${action.surface} asked for the unknown ${action.command} command; the bus routes only catalog commands.` };
13515
+ const permission = paletteactiongate({ action: entry.action, granted: input.granted, sessionactive: input.sessionactive });
13516
+ if (!permission.allowed) return { dispatched: false, gate: "paletteactiongate", reason: permission.reason ?? "The command misses its granted permission." };
13517
+ if (action.command === "starttask") {
13518
+ const proposal = taskinputproposalgate({ text: input.text ?? "", origin: input.origin ?? "", direct: false });
13519
+ if (!proposal.allowed) return { dispatched: false, gate: "taskinputproposalgate", reason: proposal.reason ?? "The task submission refuses." };
13520
+ }
13521
+ if (action.command === "stepapprove" || action.command === "diffpreview") {
13522
+ const review = planreviewgate({ reviewed: input.planreviewed, state: input.planstate });
13523
+ if (!review.allowed) return { dispatched: false, gate: "planreviewgate", reason: review.reason ?? "The plan review stays open." };
13524
+ }
13525
+ return { dispatched: true, gate: "commandbus", reason: `The ${action.command} action of the ${action.surface} routed through its policy gates and dispatches.` };
13526
+ }
13527
+
13528
+ // datagrid.ts
13529
+ function infercolumntype(values) {
13530
+ const present = values.filter((value) => value.trim() !== "");
13531
+ if (present.length === 0) return "empty";
13532
+ if (present.every((value) => /^-?\d+(?:\.\d+)?$/.test(value.trim()))) return "number";
13533
+ if (present.every((value) => value.trim() === "true" || value.trim() === "false")) return "boolean";
13534
+ if (present.every((value) => !Number.isNaN(Date.parse(value.trim())) && /\d{4}-\d{2}-\d{2}/.test(value.trim()))) return "date";
13535
+ return "text";
13536
+ }
13537
+ function datagridcolumnsof(rows) {
13538
+ const fields = [...new Set(rows.flatMap((row) => Object.keys(row)))];
13539
+ return fields.map((field) => ({ field, label: field, type: infercolumntype(rows.map((row) => row[field] ?? "")), inferred: true }));
13540
+ }
13541
+ function datagridof(input) {
13542
+ if (input.title.trim() === "") throw new Error("The datagrid view needs its title.");
13543
+ if (input.origin.trim() === "") throw new Error("The datagrid view needs its origin.");
13544
+ if (input.rows.length === 0) throw new Error("The datagrid view needs at least one extracted row.");
13545
+ const columns = datagridcolumnsof(input.rows);
13546
+ const rows = input.rows.map((row, index) => ({ index, values: Object.fromEntries(columns.map((column) => [column.field, row[column.field] ?? ""])) }));
13547
+ return { id: randomid(), title: input.title.trim(), origin: input.origin.trim(), runid: input.runid, columns, rows, at: input.at };
13548
+ }
13549
+ function sortdatagridrows(view, input) {
13550
+ const column = view.columns.find((candidate) => candidate.field === input.field);
13551
+ if (column === void 0) throw new Error(`The datagrid knows no ${input.field} column to sort.`);
13552
+ const rows = [...view.rows].sort((left, right) => {
13553
+ const leftvalue = left.values[input.field] ?? "";
13554
+ const rightvalue = right.values[input.field] ?? "";
13555
+ let compared = 0;
13556
+ if (column.type === "number") compared = Number(leftvalue) - Number(rightvalue);
13557
+ else if (column.type === "boolean") compared = (leftvalue === "true" ? 1 : 0) - (rightvalue === "true" ? 1 : 0);
13558
+ else if (column.type === "date") compared = Date.parse(leftvalue) - Date.parse(rightvalue);
13559
+ else compared = leftvalue.localeCompare(rightvalue);
13560
+ return input.direction === "descending" ? -compared : compared;
13561
+ }).map((row, index) => ({ ...row, index }));
13562
+ return { ...view, rows };
13563
+ }
13564
+ function filterdatagridrows(view, text2) {
13565
+ const query = text2.trim().toLowerCase();
13566
+ if (query === "") return view;
13567
+ const rows = view.rows.filter((row) => Object.values(row.values).some((value) => value.toLowerCase().includes(query)));
13568
+ return { ...view, rows };
13569
+ }
13570
+ function selectrowrange(view, from, to) {
13571
+ if (from < 0 || to < from || to >= view.rows.length) throw new Error(`The row range ${from} to ${to} names no inclusive slice of the ${view.rows.length} row${view.rows.length === 1 ? "" : "s"}.`);
13572
+ const rows = view.rows.map((row) => ({ ...row, selected: row.index >= from && row.index <= to }));
13573
+ return { ...view, rows };
13574
+ }
13575
+ function exportrowsof(view, scope) {
13576
+ if (scope === "selection") {
13577
+ const selected = view.rows.filter((row) => row.selected === true);
13578
+ if (selected.length === 0) throw new Error("The selection export needs its selected row range; select rows before the export.");
13579
+ return selected;
13580
+ }
13581
+ return view.rows;
13582
+ }
13583
+ function exportmenudescriptors() {
13584
+ return ["csv", "json", "clipboard"].flatMap((format) => ["selection", "step", "run"].map((scope) => ({ format, scope, destination: format === "clipboard" ? "clipboard" : "download" })));
13585
+ }
13586
+ function maskedvalueof(value, field, maskverdicts) {
13587
+ const verdict = maskverdicts[field];
13588
+ if (verdict === void 0) return { value, masked: false };
13589
+ return { value: `${"\u2022".repeat(Math.min(value.length, 8))} (${value.length} characters, masked)`, masked: true };
13590
+ }
13591
+ function csvfield(value) {
13592
+ if (/[",\n]/.test(value)) return `"${value.replaceAll('"', '""')}"`;
13593
+ return value;
13594
+ }
13595
+ function exportdatagrid(view, descriptor, maskverdicts = {}) {
13596
+ const rows = exportrowsof(view, descriptor.scope);
13597
+ const maskedfields = [...new Set(rows.flatMap((row) => Object.keys(row.values)).filter((field) => maskverdicts[field] !== void 0))];
13598
+ if (descriptor.format === "json") {
13599
+ const records = rows.map((row) => Object.fromEntries(view.columns.map((column) => {
13600
+ const masked = maskedvalueof(row.values[column.field] ?? "", column.field, maskverdicts);
13601
+ return [column.field, column.type === "number" && !masked.masked ? Number(masked.value) : column.type === "boolean" && !masked.masked ? masked.value === "true" : masked.value];
13602
+ })));
13603
+ return { format: descriptor.format, scope: descriptor.scope, destination: descriptor.destination, text: JSON.stringify({ view: view.title, origin: view.origin, runid: view.runid, columns: view.columns.map((column) => ({ field: column.field, type: column.type })), rows: records }, null, 2), rows: records.length, maskedfields };
13604
+ }
13605
+ const header = view.columns.map((column) => csvfield(column.label)).join(",");
13606
+ const lines = rows.map((row) => view.columns.map((column) => csvfield(maskedvalueof(row.values[column.field] ?? "", column.field, maskverdicts).value)).join(","));
13607
+ return { format: descriptor.format, scope: descriptor.scope, destination: descriptor.destination, text: [header, ...lines].join("\n"), rows: rows.length, maskedfields };
13608
+ }
13609
+
13610
+ // quickactions.ts
13611
+ function quickactioncatalog() {
13612
+ return [
13613
+ { id: "extractpage", label: "Extract page data", command: "starttask", surface: "sidepanel", session: true },
13614
+ { id: "captureshot", label: "Capture a shot", command: "starttask", surface: "sidepanel", permission: "downloads", session: true },
13615
+ { id: "runrecent", label: "Run the recent task", command: "starttask", surface: "popup", session: true },
13616
+ { id: "opendashboardpage", label: "Open the dashboard", command: "opendashboardpage", surface: "dashboardpage" }
13617
+ ];
13618
+ }
13619
+ function quickactionsfor(catalog, input) {
13620
+ const capabilities = input.grantedcapabilities ?? ["activeTab", "storage", "scripting", "sidePanel"];
13621
+ const grantedcapabilities = capabilities;
13622
+ return catalog.filter((action) => quickactiongate({ action: { command: action.command, origin: input.origin, ...action.permission !== void 0 ? { permission: action.permission } : {}, ...action.session !== void 0 ? { session: action.session } : {} }, granted: input.granted, sessionactive: input.sessionactive, capabilities: grantedcapabilities }).allowed);
13623
+ }
13624
+ function shortcutdefaults() {
13625
+ return [
13626
+ { command: "starttask", key: "Enter", modifiers: [], editable: true, surface: "popup" },
13627
+ { command: "pauserun", key: "p", modifiers: ["ctrl", "shift"], editable: true, surface: "sidepanel" },
13628
+ { command: "resumerun", key: "r", modifiers: ["ctrl", "shift"], editable: true, surface: "sidepanel" },
13629
+ { command: "cancelrun", key: "x", modifiers: ["ctrl", "shift"], editable: true, surface: "sidepanel" },
13630
+ { command: "commandpalette", key: ".", modifiers: ["ctrl"], editable: true, surface: "popup" }
13631
+ ];
13632
+ }
13633
+ function parseshortcut(text2) {
13634
+ const parts = text2.trim().toLowerCase().split("+").map((part) => part.trim()).filter((part) => part !== "");
13635
+ if (parts.length === 0) throw new Error("The shortcut binding needs its key.");
13636
+ const modifiers = ["ctrl", "alt", "shift", "meta"];
13637
+ const key = parts.filter((part) => !modifiers.includes(part))[0];
13638
+ if (key === void 0 || key === "") throw new Error("The shortcut binding needs its key beside its modifiers.");
13639
+ return { key, modifiers: parts.filter((part) => modifiers.includes(part)) };
13640
+ }
13641
+ function shortcuttext(binding) {
13642
+ return [...binding.modifiers, binding.key].join("+");
13643
+ }
13644
+ function shortcutbindingafter(bindings, command, text2) {
13645
+ const existing = bindings.find((binding) => binding.command === command);
13646
+ if (existing === void 0) throw new Error(`The shortcutkeys know no ${command} command to edit.`);
13647
+ const parsed = parseshortcut(text2);
13648
+ return bindings.map((binding) => binding.command === command ? { ...binding, key: parsed.key, modifiers: parsed.modifiers } : binding);
13649
+ }
13650
+ function shortcutcommandof(bindings, input) {
13651
+ const pressed = [...input.modifiers].map((modifier) => modifier.toLowerCase()).sort();
13652
+ return bindings.find((binding) => binding.key.toLowerCase() === input.key.toLowerCase() && [...binding.modifiers].sort().join("+") === pressed.join("+") && (binding.command === "commandpalette" || binding.surface === input.surface))?.command;
13653
+ }
13654
+ function shortcutdispatchable(command, entries, input) {
13655
+ const entry = entries.find((candidate) => candidate.action.command === command);
13656
+ if (entry === void 0) return command === "commandpalette";
13657
+ return paletteactiongate({ action: { command: entry.action.command, ...entry.action.permission !== void 0 ? { permission: entry.action.permission } : {}, ...entry.action.session !== void 0 ? { session: entry.action.session } : {} }, granted: input.granted, sessionactive: input.sessionactive }).allowed;
13658
+ }
13659
+ function parseomniboxtask(input) {
13660
+ const text2 = input.text.trim();
13661
+ if (text2 === "") throw new Error("The omnibox task needs its natural language goal after the keyword.");
13662
+ if (input.origin.trim() === "") throw new Error("The omnibox task needs its active origin scope.");
13663
+ return { id: randomid(), text: text2, origin: input.origin.trim(), surface: "omnibox", at: input.at };
13664
+ }
13665
+ function omniboxtasktotaskinput(submission) {
13666
+ return { id: submission.id, text: submission.text, context: "", origin: submission.origin, surface: "omnibox", at: submission.at };
13667
+ }
13668
+
13669
+ // statusviews.ts
13670
+ function statusbadgeof(input) {
13671
+ if (input.planstate === void 0) return { state: "idle", waitingcount: 0 };
13672
+ if (input.waitingcount > 0) return { state: "attention", waitingcount: input.waitingcount, ...input.runid !== void 0 ? { runid: input.runid } : {} };
13673
+ if (input.planstate === "approved") return { state: "running", waitingcount: 0, ...input.runid !== void 0 ? { runid: input.runid } : {} };
13674
+ if (input.planstate === "pending") return { state: "waiting", waitingcount: 0, ...input.runid !== void 0 ? { runid: input.runid } : {} };
13675
+ return { state: "idle", waitingcount: 0, ...input.runid !== void 0 ? { runid: input.runid } : {} };
13676
+ }
13677
+ function badgetextof(state) {
13678
+ if (state.state === "attention") return String(state.waitingcount);
13679
+ if (state.state === "running") return "run";
13680
+ if (state.state === "waiting") return "wait";
13681
+ return "";
13682
+ }
13683
+ function badgecolorof(state) {
13684
+ if (state.state === "attention") return "#b3261e";
13685
+ if (state.state === "running") return "#1a73e8";
13686
+ if (state.state === "waiting") return "#e37400";
13687
+ return "#5f6368";
13688
+ }
13689
+ function notifydoneof(input) {
13690
+ if (input.runid.trim() === "") throw new Error("The done notification needs its run id.");
13691
+ return { id: randomid(), kind: "done", title: "The run completed", body: input.summary.trim() === "" ? `The run of ${input.origin} completed; the runsummary holds every step outcome.` : input.summary, deeplink: `#run-${input.runid}`, runid: input.runid, content: false, at: input.at };
13692
+ }
13693
+ function notifyattentionof(input) {
13694
+ if (input.stepid.trim() === "") throw new Error("The attention notification needs its waiting step.");
13695
+ const gate = notificationcontentgate({ content: input.content === true, consent: input.consent === true });
13696
+ if (!gate.allowed) throw new Error(gate.reason ?? "The attention notification refuses its page content.");
13697
+ return { id: randomid(), kind: "attention", title: input.cause === "gatewait" ? "The run waits for review" : input.cause === "phishguard" ? "The phishguard blocked a step" : "The run deferred a step", body: input.reason, deeplink: `#step-${input.stepid}`, runid: input.runid, stepid: input.stepid, content: input.content === true, at: input.at };
13698
+ }
13699
+ function notificationrespectsdnd(payload, dnd) {
13700
+ if (dnd) return { show: false, reason: `The os stays in do not disturb, so the ${payload.kind} notification holds its deep link ${payload.deeplink} in the history instead of showing.` };
13701
+ return { show: true, reason: `The ${payload.kind} notification shows with its deep link ${payload.deeplink}.` };
13702
+ }
13703
+ function recenttrayentryof(input) {
13704
+ if (input.runid.trim() === "") throw new Error("The recenttray entry needs its run id.");
13705
+ return { runid: input.runid, origin: input.origin, outcome: input.outcome, title: input.title, at: input.at, resumable: input.outcome === "halted", reopenable: input.outcome === "completed" || input.outcome === "failed" };
13706
+ }
13707
+ function recenttrayafter(entries, entry, depth) {
13708
+ const appended = [entry, ...entries.filter((candidate) => candidate.runid !== entry.runid)];
13709
+ if (depth === void 0) return appended;
13710
+ if (!Number.isInteger(depth) || depth <= 0) return appended;
13711
+ return appended.slice(0, depth);
13712
+ }
13713
+ function recenttrayactions(entry) {
13714
+ const actions = [];
13715
+ if (entry.resumable) actions.push("resume");
13716
+ if (entry.reopenable) actions.push("reopen");
13717
+ return actions;
13718
+ }
13719
+ function stetoastof(input) {
13720
+ if (input.stepid.trim() === "") throw new Error("The stetoast needs its step.");
13721
+ return { id: randomid(), stepid: input.stepid, kind: input.kind, durationms: input.durationms, at: input.at };
13722
+ }
13723
+ function stetoaststackafter(toasts, toast, livecount) {
13724
+ const history = [...toasts, toast];
13725
+ if (livecount === void 0 || !Number.isInteger(livecount) || livecount <= 0) return { live: history, history };
13726
+ return { live: history.slice(-livecount), history };
13727
+ }
13728
+ function stetoasthistory(toasts) {
13729
+ return [...toasts].reverse();
13730
+ }
13731
+
13732
+ // pickerviews.ts
13733
+ function stabilityscoreof(input) {
13734
+ let score = 0;
13735
+ if (input.hasid) score += 40;
13736
+ if (input.hasstableattributes) score += 25;
13737
+ if (input.hasrole) score += 15;
13738
+ if (input.textunique) score += 10;
13739
+ if (input.selector.trim() === "") score -= 20;
13740
+ else if (input.selector.includes(":nth-child") || input.selector.includes(":nth-of-type")) score -= 15;
13741
+ return Math.max(0, Math.min(100, score));
13742
+ }
13743
+ function pickercandidateof(input) {
13744
+ const score = stabilityscoreof(input);
13745
+ const reasons = [];
13746
+ if (input.hasid) reasons.push("the id anchors the selector");
13747
+ if (input.hasstableattributes) reasons.push("stable attributes back the selector");
13748
+ if (input.hasrole) reasons.push("the aria role names the element");
13749
+ if (input.textunique) reasons.push("the text stays unique on the page");
13750
+ if (reasons.length === 0) reasons.push("only the positional shape anchors the selector");
13751
+ return { selector: input.selector, ...input.text !== void 0 && input.text !== "" ? { text: input.text } : {}, ...input.role !== void 0 && input.role !== "" ? { role: input.role } : {}, stabilityscore: score, reason: `The stability score of ${score} stands because ${reasons.join(", ")}.` };
13752
+ }
13753
+ function pickersessionstart(input) {
13754
+ const gate = pickeroverlaygate({ origin: input.origin, granted: input.granted });
13755
+ if (!gate.allowed) throw new Error(gate.reason);
13756
+ return { id: randomid(), origin: input.origin, candidates: rankcandidates(input.candidates), startedat: input.at };
13757
+ }
13758
+ function rankcandidates(candidates) {
13759
+ return [...candidates].sort((left, right) => right.stabilityscore - left.stabilityscore);
13760
+ }
13761
+ function lockcandidate(session, candidateindex, stepid) {
13762
+ const candidate = session.candidates[candidateindex];
13763
+ if (candidate === void 0) throw new Error(`The picker session knows no candidate ${candidateindex} to lock.`);
13764
+ if (session.lockedstepid !== void 0) throw new Error(`The picker session already locks its candidate for the step ${session.lockedstepid}; one session locks one candidate.`);
13765
+ return { ...session, lockedstepid: stepid, lockedselector: candidate.selector };
13766
+ }
13767
+ function haloof(input) {
13768
+ if (input.selector.trim() === "") throw new Error("The targethalo needs its target selector.");
13769
+ return { stepid: input.stepid, selector: input.selector, rect: input.rect, state: input.state };
13770
+ }
13771
+ function halocolorof(state) {
13772
+ if (state === "running") return "#1a73e8";
13773
+ if (state === "waiting") return "#e37400";
13774
+ if (state === "done") return "#188038";
13775
+ if (state === "failed") return "#b3261e";
13776
+ if (state === "halted") return "#3c4043";
13777
+ return "#5f6368";
13778
+ }
13779
+ function guidedtips() {
13780
+ return [
13781
+ { id: "selectorstability", surface: "sidepanel", title: "Selector stability", body: "Devthink scores every candidate selector by its stability: an id anchor, stable attributes, an aria role and a unique text each lift the score while a positional shape lowers it, so the proposed step binds to the selector least likely to break.", pickerstep: "candidatepick" },
13782
+ { id: "candidatelock", surface: "sidepanel", title: "Locking a candidate", body: "Lock one candidate to bind it to the proposed step; one picker session locks one candidate and the locked selector rides the step for its review.", pickerstep: "candidatelock" },
13783
+ { id: "haloreadout", surface: "sidepanel", title: "The halo read out", body: "During a run the targethalo outlines the active target element and its color follows the step state: gray while pending, blue while running, amber at a gate, green when done, red on failure and dark when halted.", pickerstep: "halotracking" }
13784
+ ];
13785
+ }
13786
+ function guidedtipdismiss(tips, dismissed, tipid) {
13787
+ const tip = tips.find((candidate) => candidate.id === tipid);
13788
+ if (tip === void 0) throw new Error(`The guidedtips know no ${tipid} tip.`);
13789
+ return [.../* @__PURE__ */ new Set([...dismissed, tipid])];
13790
+ }
13791
+ function guidedtiprecall(dismissed) {
13792
+ return [];
13793
+ }
13794
+ function pagechipof(input) {
13795
+ if (input.stepid.trim() === "") throw new Error("The pagechip needs its step.");
13796
+ if (input.selector.trim() === "") throw new Error("The pagechip needs its anchor selector.");
13797
+ return { id: randomid(), stepid: input.stepid, selector: input.selector, origin: input.origin, at: input.at };
13798
+ }
13799
+ function pagechipresolve(chip, resolution, surface, at) {
13800
+ if (surface === "background") throw new Error("The pagechip resolution needs its distinct human action from a surface; the background never resolves a review on its own.");
13801
+ const resolved = { ...chip, resolution, resolvedat: at };
13802
+ return {
13803
+ chip: resolved,
13804
+ logevent: { kind: "review", stepid: chip.stepid, summary: `The user ${resolution === "approve" ? "approved" : "rejected"} the step ${chip.stepid} of ${chip.origin} from the pagechip anchored to ${chip.selector} on the ${surface}; one distinct human action resolved the step alone.` }
13805
+ };
13806
+ }
13807
+
13808
+ // evidenceviews.ts
13809
+ function shotpanelof(input) {
13810
+ const gate = shotpanelgate({ captureorigin: input.origin, granted: input.granted });
13811
+ if (!gate.allowed) throw new Error(gate.reason);
13812
+ if (input.stepid.trim() === "") throw new Error("The shotpanel view needs its step.");
13813
+ return { id: randomid(), stepid: input.stepid, runid: input.runid, captureid: input.captureid, provenance: input.provenance, origin: input.origin, redactions: input.redactions ?? [], zoom: 1, pan: { x: 0, y: 0 }, at: input.at };
13814
+ }
13815
+ function shotpanelzoom(view, factor) {
13816
+ if (!(factor > 0)) throw new Error("The shotpanel zoom factor stays a positive number.");
13817
+ return { ...view, zoom: view.zoom * factor };
13818
+ }
13819
+ function shotpanelpan(view, offset) {
13820
+ return { ...view, pan: { x: view.pan.x + offset.x, y: view.pan.y + offset.y } };
13821
+ }
13822
+ function comparepairof(input) {
13823
+ if (input.stepid.trim() === "") throw new Error("The compareviewer pair needs its step.");
13824
+ if (input.beforecaptureid === input.aftercaptureid) throw new Error("The compareviewer pair needs its distinct before and after captures.");
13825
+ return { id: randomid(), stepid: input.stepid, beforecaptureid: input.beforecaptureid, aftercaptureid: input.aftercaptureid, slidervalue: 50 };
13826
+ }
13827
+ function overlayslider(pair, value) {
13828
+ if (!Number.isFinite(value) || value < 0 || value > 100) throw new Error("The compareviewer slider stays between zero and one hundred.");
13829
+ return { ...pair, slidervalue: value };
13830
+ }
13831
+ function comparepairsforsteps(steps, captures) {
13832
+ const pairs = [];
13833
+ for (const step of steps) {
13834
+ if (!step.writeexecuted) continue;
13835
+ const capture = captures[step.stepid];
13836
+ if (capture?.beforecaptureid === void 0 || capture?.aftercaptureid === void 0) continue;
13837
+ pairs.push(comparepairof({ stepid: step.stepid, beforecaptureid: capture.beforecaptureid, aftercaptureid: capture.aftercaptureid }));
13838
+ }
13839
+ return pairs;
13840
+ }
13841
+
13842
+ // siteprefs.ts
13843
+ function siteprofileof(input) {
13844
+ const gate = siteprofilegate({ origin: input.origin });
13845
+ if (!gate.allowed) throw new Error(gate.reason);
13846
+ return { origin: input.origin, ...input.theme !== void 0 ? { theme: input.theme } : {}, ...input.shortcuts !== void 0 ? { shortcuts: input.shortcuts } : {}, ...input.defaultview !== void 0 ? { defaultview: input.defaultview } : {}, updatedat: input.at };
13847
+ }
13848
+ function siteprofileactive(profile, origin) {
13849
+ return profile.origin === origin;
13850
+ }
13851
+ function siteprofilefor(profiles, origin) {
13852
+ return profiles.find((profile) => siteprofileactive(profile, origin));
13853
+ }
13854
+ function darklighttokensof(mode) {
13855
+ const tokens = mode === "dark" ? { surface: "#1f1f1f", elevated: "#2b2b2b", text: "#e3e3e3", muted: "#9aa0a6", accent: "#8ab4f8", border: "#3c4043", focus: "#aecbfa", error: "#f28b82", success: "#81c995", warning: "#fdd663" } : { surface: "#ffffff", elevated: "#f8f9fa", text: "#202124", muted: "#5f6368", accent: "#1a73e8", border: "#dadce0", focus: "#174ea6", error: "#b3261e", success: "#188038", warning: "#e37400" };
13856
+ return { mode, tokens };
13857
+ }
13858
+ function resolveappearance(input) {
13859
+ if (input.siteprofile?.theme !== void 0 && input.siteprofile.theme !== "system") return { ...darklighttokensof(input.siteprofile.theme), source: "site" };
13860
+ if (input.useroverride !== void 0 && input.useroverride !== "system") return { ...darklighttokensof(input.useroverride), source: "user" };
13861
+ return { ...darklighttokensof(input.ospreference), source: "os" };
13862
+ }
13863
+ function applytheme(documentroot, tokens) {
13864
+ for (const [name, value] of Object.entries(tokens.tokens)) documentroot.style.setProperty(`--theme-${name}`, value);
13865
+ documentroot.style.setProperty("color-scheme", tokens.mode);
13866
+ }
13867
+ function localebundles() {
13868
+ return [
13869
+ {
13870
+ language: "en",
13871
+ strings: {
13872
+ "popup.title": "Devthink",
13873
+ "popup.taskinput.placeholder": "Describe the goal for the active tab",
13874
+ "popup.taskinput.submit": "Propose the plan",
13875
+ "popup.palette.open": "Open the commandpalette",
13876
+ "popup.recent.title": "Recent runs",
13877
+ "popup.recent.resume": "Resume",
13878
+ "popup.recent.reopen": "Reopen",
13879
+ "sidepanel.tab.plan": "Plan",
13880
+ "sidepanel.tab.run": "Run",
13881
+ "sidepanel.tab.review": "Review",
13882
+ "sidepanel.data.export": "Export",
13883
+ "dashboard.title": "Dashboard",
13884
+ "options.title": "Options",
13885
+ "options.theme.label": "Theme",
13886
+ "options.theme.dark": "Dark",
13887
+ "options.theme.light": "Light",
13888
+ "options.theme.system": "Follow the system",
13889
+ "options.locale.label": "Language",
13890
+ "options.shortcuts.label": "Shortcutkeys",
13891
+ "options.notifications.label": "Notifications",
13892
+ "options.importexport.label": "Import and export",
13893
+ "options.tour.label": "Feature tour",
13894
+ "stepapprove.approve": "Approve",
13895
+ "stepapprove.reject": "Reject",
13896
+ "stepapprove.edit": "Edit",
13897
+ "pagechip.approve": "Approve",
13898
+ "pagechip.reject": "Reject",
13899
+ "grid.empty": "No extracted rows yet",
13900
+ "toast.stepdone": "Step completed"
13901
+ }
13902
+ },
13903
+ {
13904
+ language: "pt",
13905
+ strings: {
13906
+ "popup.title": "Devthink",
13907
+ "popup.taskinput.placeholder": "Descreva o objetivo para a aba ativa",
13908
+ "popup.taskinput.submit": "Propor o plano",
13909
+ "popup.palette.open": "Abrir a paleta de comandos",
13910
+ "popup.recent.title": "Execu\xE7\xF5es recentes",
13911
+ "popup.recent.resume": "Retomar",
13912
+ "popup.recent.reopen": "Reabrir",
13913
+ "sidepanel.tab.plan": "Plano",
13914
+ "sidepanel.tab.run": "Execu\xE7\xE3o",
13915
+ "sidepanel.tab.review": "Revis\xE3o",
13916
+ "sidepanel.data.export": "Exportar",
13917
+ "dashboard.title": "Painel",
13918
+ "options.title": "Op\xE7\xF5es",
13919
+ "options.theme.label": "Tema",
13920
+ "options.theme.dark": "Escuro",
13921
+ "options.theme.light": "Claro",
13922
+ "options.theme.system": "Seguir o sistema",
13923
+ "options.locale.label": "Idioma",
13924
+ "options.shortcuts.label": "Atalhos",
13925
+ "options.notifications.label": "Notifica\xE7\xF5es",
13926
+ "options.importexport.label": "Importar e exportar",
13927
+ "options.tour.label": "Tour de recursos",
13928
+ "stepapprove.approve": "Aprovar",
13929
+ "stepapprove.reject": "Rejeitar",
13930
+ "stepapprove.edit": "Editar",
13931
+ "pagechip.approve": "Aprovar",
13932
+ "pagechip.reject": "Rejeitar",
13933
+ "grid.empty": "Nenhuma linha extra\xEDda ainda",
13934
+ "toast.stepdone": "Etapa conclu\xEDda"
13935
+ }
13936
+ }
13937
+ ];
13938
+ }
13939
+ function localestring(bundles, language, key) {
13940
+ const requested = bundles.find((bundle) => bundle.language === language);
13941
+ const english = bundles.find((bundle) => bundle.language === "en");
13942
+ return requested?.strings[key] ?? english?.strings[key] ?? key;
13943
+ }
13944
+ function supportedlanguages(bundles) {
13945
+ return bundles.map((bundle) => bundle.language);
13946
+ }
13947
+ function localeformat(input) {
13948
+ if (input.kind === "date") {
13949
+ const date = new Date(input.value);
13950
+ const year = date.getUTCFullYear();
13951
+ const month = String(date.getUTCMonth() + 1).padStart(2, "0");
13952
+ const day = String(date.getUTCDate()).padStart(2, "0");
13953
+ const hours = String(date.getUTCHours()).padStart(2, "0");
13954
+ const minutes = String(date.getUTCMinutes()).padStart(2, "0");
13955
+ return input.language === "pt" ? `${day}/${month}/${year} ${hours}:${minutes}` : `${year}-${month}-${day} ${hours}:${minutes}`;
13956
+ }
13957
+ if (input.kind === "duration") {
13958
+ const seconds = Math.round(input.value / 1e3);
13959
+ const minutes = Math.floor(seconds / 60);
13960
+ const rest = seconds % 60;
13961
+ return input.language === "pt" ? `${minutes} min ${rest} s` : `${minutes}m ${rest}s`;
13962
+ }
13963
+ const text2 = String(input.value);
13964
+ const parts = text2.split(".");
13965
+ const whole = parts[0] ?? "0";
13966
+ const fraction = parts[1];
13967
+ const grouped = whole.replace(/\B(?=(\d{3})+(?!\d))/g, input.language === "pt" ? "." : ",");
13968
+ return fraction !== void 0 ? `${grouped}${input.language === "pt" ? "," : "."}${fraction}` : grouped;
13969
+ }
13970
+
13971
+ // portability.ts
13972
+ function importexportpayloadof(input) {
13973
+ if (input.profile.trim() === "") throw new Error("The importexport payload needs its profile name.");
13974
+ const secrets = [...input.originprofiles, ...input.siteprofiles, ...input.notes, ...Object.values(input.preferences)].find((record2) => secretcarrying(record2)) !== void 0;
13975
+ const gate = importexportgate({ containssecrets: secrets, unmaskedlogs: false });
13976
+ if (!gate.allowed) throw new Error(gate.reason);
13977
+ return { version: 1, kind: "settings", profile: input.profile.trim(), exportedat: input.at, contents: { originprofiles: input.originprofiles, siteprofiles: input.siteprofiles, notes: input.notes, preferences: input.preferences }, exclusions: ["secretvault values", "unmasked logs"] };
13978
+ }
13979
+ function secretcarrying(record2) {
13980
+ if (record2 === null || typeof record2 !== "object") return false;
13981
+ const entries = Object.entries(record2);
13982
+ const secretkeys = ["secret", "token", "password", "apikey", "authorization"];
13983
+ return entries.some(([key, value]) => secretkeys.some((shape) => key.toLowerCase().includes(shape)) && typeof value === "string" && value.trim() !== "");
13984
+ }
13985
+ function importexportvalidate(payload) {
13986
+ const records = [...payload.contents.originprofiles, ...payload.contents.siteprofiles, ...payload.contents.notes, ...Object.values(payload.contents.preferences)];
13987
+ const preferencessecrets = Object.entries(payload.contents.preferences).some(([key, value]) => secretcarrying({ [key]: value }));
13988
+ const gate = importexportgate({ containssecrets: records.some((record2) => secretcarrying(record2)) || preferencessecrets, unmaskedlogs: payload.contents.unmaskedlogs !== void 0 });
13989
+ if (!gate.allowed) return { ok: false, reason: gate.reason ?? "The importexport bundle refuses." };
13990
+ if (payload.profile.trim() === "") return { ok: false, reason: "The importexport bundle needs its profile name." };
13991
+ return { ok: true, reason: `The importexport bundle of the profile ${payload.profile} validates with ${payload.contents.originprofiles.length} origin profile${payload.contents.originprofiles.length === 1 ? "" : "s"}, ${payload.contents.siteprofiles.length} site profile${payload.contents.siteprofiles.length === 1 ? "" : "s"} and ${payload.contents.notes.length} note${payload.contents.notes.length === 1 ? "" : "s"}; ${payload.exclusions.join(" and ")} never enter any bundle.` };
13992
+ }
13993
+ function applyimport(payload, current) {
13994
+ const validation = importexportvalidate(payload);
13995
+ if (!validation.ok) throw new Error(validation.reason);
13996
+ const applied = Object.keys(payload.contents.preferences);
13997
+ return { preferences: { ...current, ...payload.contents.preferences }, applied };
13998
+ }
13999
+ function detectfilekind(filename, head) {
14000
+ const extension = filename.toLowerCase().split(".").pop() ?? "";
14001
+ if (extension === "csv") return "csv";
14002
+ if (extension === "json") {
14003
+ const trimmed = head.trim();
14004
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) return trimmed.includes('"steps"') ? "workflow" : "json";
14005
+ return "json";
14006
+ }
14007
+ if (extension === "yaml" || extension === "yml") return "workflow";
14008
+ return void 0;
14009
+ }
14010
+ function dropimportof(input) {
14011
+ if (input.filename.trim() === "") throw new Error("The dropimport session needs its filename.");
14012
+ const kind = detectfilekind(input.filename, input.head);
14013
+ if (kind === void 0) throw new Error(`The dropimport detects no csv, json or workflow kind in ${input.filename}; the import path refuses the file.`);
14014
+ return { id: `${input.filename}:${input.at}`, filename: input.filename, kind, bytes: input.bytes, accepted: true, at: input.at };
14015
+ }
14016
+
14017
+ // tourviews.ts
14018
+ function featuretourstops() {
14019
+ return [
14020
+ { id: "origingrants", surface: "popup", focus: "#allowlist", title: "Origin grants", body: "Devthink denies automation by default; grant one exact origin at a time and every run stays inside the granted origins.", order: 1 },
14021
+ { id: "planreview", surface: "sidepanel", focus: "#plancards", title: "Plan review", body: "Every task becomes a plan of reviewed steps; read the plancards of each risk class and approve, reject or edit one step at a time.", order: 2 },
14022
+ { id: "runcontrol", surface: "sidepanel", focus: "#timeline", title: "Run control", body: "Runs start, pause, resume and cancel under your hand while the stepstimeline follows every transition.", order: 3 },
14023
+ { id: "logaudit", surface: "dashboardpage", focus: "#sessiongrid", title: "Log audit", body: "The immutable log chains every step transition with masked values; verify the chain and copy a verified range as an audit excerpt.", order: 4 },
14024
+ { id: "datagrid", surface: "sidepanel", focus: "#datagrid", title: "The datagrid", body: "Extraction results render as a grid with inferred column types; sort and filter locally, select a row range and export csv, json or clipboard with masked values only.", order: 5 },
14025
+ { id: "compareviewer", surface: "sidepanel", focus: "#compareviewer", title: "The compareviewer", body: "Every executed write step pairs its before and after captures; the slider overlays the two so you see exactly what the step changed.", order: 6 },
14026
+ { id: "pickeroverlay", surface: "sidepanel", focus: "#picker", title: "The pickeroverlay", body: "Start a picker session to list the element candidates of the granted origin with stability scored selectors; lock one candidate for the proposed step.", order: 7 }
14027
+ ];
14028
+ }
14029
+ function featuretourordered(stops) {
14030
+ return [...stops].sort((left, right) => left.order - right.order);
14031
+ }
14032
+ function featuretourstopat(stops, position) {
14033
+ return featuretourordered(stops)[position];
14034
+ }
14035
+ function a11ylabelof(input) {
14036
+ if (input.control.trim() === "") throw new Error("The a11ylabel needs its control.");
14037
+ if (input.name.trim() === "") throw new Error("The a11ylabel needs its accessible name.");
14038
+ return { control: input.control, role: input.role, name: input.name, ...input.state !== void 0 ? { state: input.state } : {}, ...input.value !== void 0 ? { value: input.value } : {} };
14039
+ }
14040
+ function a11ylabelsfor(surface) {
14041
+ const labels = {
14042
+ popup: [
14043
+ a11ylabelof({ control: "taskinput", role: "textbox", name: "popup.taskinput.placeholder", state: "idle" }),
14044
+ a11ylabelof({ control: "submit", role: "button", name: "popup.taskinput.submit" }),
14045
+ a11ylabelof({ control: "palette", role: "button", name: "popup.palette.open" }),
14046
+ a11ylabelof({ control: "recenttray", role: "list", name: "popup.recent.title", value: "0 runs" })
14047
+ ],
14048
+ sidepanel: [
14049
+ a11ylabelof({ control: "plantab", role: "tab", name: "sidepanel.tab.plan", state: "selected" }),
14050
+ a11ylabelof({ control: "runtab", role: "tab", name: "sidepanel.tab.run", state: "unselected" }),
14051
+ a11ylabelof({ control: "reviewtab", role: "tab", name: "sidepanel.tab.review", state: "unselected" }),
14052
+ a11ylabelof({ control: "datagrid", role: "table", name: "grid.empty" }),
14053
+ a11ylabelof({ control: "compareviewer", role: "slider", name: "sidepanel.data.compare", value: "50" }),
14054
+ a11ylabelof({ control: "picker", role: "button", name: "sidepanel.data.picker" })
14055
+ ],
14056
+ dashboardpage: [
14057
+ a11ylabelof({ control: "sessiongrid", role: "table", name: "dashboard.title", value: "0 runs" }),
14058
+ a11ylabelof({ control: "historysearch", role: "search", name: "dashboard.history" }),
14059
+ a11ylabelof({ control: "dropzone", role: "region", name: "options.importexport.label" })
14060
+ ],
14061
+ optionspage: [
14062
+ a11ylabelof({ control: "theme", role: "radiogroup", name: "options.theme.label", value: "system" }),
14063
+ a11ylabelof({ control: "locale", role: "combobox", name: "options.locale.label", value: "en" }),
14064
+ a11ylabelof({ control: "shortcuts", role: "group", name: "options.shortcuts.label" }),
14065
+ a11ylabelof({ control: "notifications", role: "switch", name: "options.notifications.label", state: "off" }),
14066
+ a11ylabelof({ control: "importexport", role: "region", name: "options.importexport.label" }),
14067
+ a11ylabelof({ control: "tour", role: "button", name: "options.tour.label" })
14068
+ ],
14069
+ onboarding: [
14070
+ a11ylabelof({ control: "onboarding", role: "dialog", name: "options.tour.label", state: "open" })
14071
+ ],
14072
+ omnibox: [
14073
+ a11ylabelof({ control: "omnibox", role: "textbox", name: "popup.taskinput.placeholder" })
14074
+ ],
14075
+ page: [
14076
+ a11ylabelof({ control: "pagechip", role: "group", name: "pagechip.approve", state: "pending" })
14077
+ ]
14078
+ };
14079
+ return labels[surface];
14080
+ }
14081
+ function a11ylabellocalized(label, bundles, language) {
14082
+ return { ...label, name: localestring(bundles, language, label.name) };
14083
+ }
14084
+ function a11ylabelslocalizedfor(surface, bundles, language) {
14085
+ return a11ylabelsfor(surface).map((label) => a11ylabellocalized(label, bundles, language));
14086
+ }
14087
+
13059
14088
  // taskqueue.ts
13060
14089
  function emptyqueue(input = {}) {
13061
14090
  return { lanes: input.lanes ?? [], priorities: input.priorities ?? [], completionpolicy: input.completionpolicy ?? "all", items: [], claims: [] };
@@ -14009,6 +15038,12 @@ function logchainreport(input) {
14009
15038
  function transparencyreport(input) {
14010
15039
  return { version: protocolversion, posture: "denydefault", grants: input.grants, windows: input.windows, connectallow: input.connectallow, permdiffs: input.permdiffs, safedefaults: input.safedefaults, vault: input.vault };
14011
15040
  }
15041
+ function surfacesnapshot(input) {
15042
+ return { version: protocolversion, surface: input.surface, palette: input.palette, timeline: input.timeline, logstream: input.logstream, plancards: input.plancards, ...input.onboarding !== void 0 ? { onboarding: input.onboarding } : {} };
15043
+ }
15044
+ function interfaceviews(input) {
15045
+ return { version: protocolversion, ...input.datagrid !== void 0 ? { datagrid: input.datagrid } : {}, exportmenu: input.exportmenu, badge: input.badge, recenttray: input.recenttray, toasts: input.toasts, appearance: input.appearance };
15046
+ }
14012
15047
 
14013
15048
  // workfloweditor.ts
14014
15049
  var palettecategories = ["actions", "controlflow", "waits", "variables", "triggers"];
@@ -14714,12 +15749,17 @@ function yamlscalarvalue(text2) {
14714
15749
  return text2;
14715
15750
  }
14716
15751
  export {
15752
+ a11ylabellocalized,
15753
+ a11ylabelof,
15754
+ a11ylabelsfor,
15755
+ a11ylabelslocalizedfor,
14717
15756
  acceptrenderresult,
14718
15757
  acceptworkerresponse,
14719
15758
  ackreview,
14720
15759
  acquirelock,
14721
15760
  acquirerunlock,
14722
15761
  activelayers,
15762
+ activetimelineanchor,
14723
15763
  addedge,
14724
15764
  addhistoryentry,
14725
15765
  addnode,
@@ -14745,13 +15785,16 @@ export {
14745
15785
  apikeyconsentgranted,
14746
15786
  apireplayspecof,
14747
15787
  appendlogentry,
15788
+ appendlogstreamevent,
14748
15789
  applycooldown,
14749
15790
  applyheaderules,
15791
+ applyimport,
14750
15792
  applylayer,
14751
15793
  applyoverride,
14752
15794
  applyretry,
14753
15795
  applyreview,
14754
15796
  applyruntimeout,
15797
+ applytheme,
14755
15798
  applytimeout,
14756
15799
  approvalframes,
14757
15800
  approvalprompt,
@@ -14764,6 +15807,7 @@ export {
14764
15807
  attachcdpsession,
14765
15808
  attachtargetof,
14766
15809
  attachtimeline,
15810
+ auditexcerptof,
14767
15811
  authconsentgranted,
14768
15812
  authorizeurl,
14769
15813
  authrefusedmessage,
@@ -14771,6 +15815,8 @@ export {
14771
15815
  autointervalof,
14772
15816
  automationallowlistgate,
14773
15817
  backoffdelay,
15818
+ badgecolorof,
15819
+ badgetextof,
14774
15820
  batchreport,
14775
15821
  beatrun,
14776
15822
  bindlocalhost,
@@ -14795,6 +15841,8 @@ export {
14795
15841
  breakpointbudgetallowed,
14796
15842
  breakpointceilingof,
14797
15843
  breakpointinputof,
15844
+ broadcastchannelof,
15845
+ broadcastframeof,
14798
15846
  broadcastrecipient,
14799
15847
  browserpermissions,
14800
15848
  bucketboundsvalid,
@@ -14809,6 +15857,7 @@ export {
14809
15857
  buildstitchplan,
14810
15858
  buildtoolcatalog,
14811
15859
  bumprevision,
15860
+ busrouteaction,
14812
15861
  callgraphql,
14813
15862
  calllocal,
14814
15863
  calllogreport,
@@ -14864,6 +15913,8 @@ export {
14864
15913
  collectresults,
14865
15914
  commandguard,
14866
15915
  compareoutputs,
15916
+ comparepairof,
15917
+ comparepairsforsteps,
14867
15918
  complete,
14868
15919
  composeworkflow,
14869
15920
  conditionof,
@@ -14911,6 +15962,9 @@ export {
14911
15962
  croprect,
14912
15963
  crossesviewport,
14913
15964
  cursorfrom,
15965
+ darklighttokensof,
15966
+ datagridcolumnsof,
15967
+ datagridof,
14914
15968
  datasetresponse,
14915
15969
  debuggate,
14916
15970
  debuggerconsentcovers,
@@ -14939,7 +15993,10 @@ export {
14939
15993
  denydefaultposture,
14940
15994
  actionrisk as deriveactionrisk,
14941
15995
  detachcdpsession,
15996
+ detectfilekind,
14942
15997
  devicepresetof,
15998
+ diffpreviewgate,
15999
+ diffpreviewof,
14943
16000
  diffresponse,
14944
16001
  diffreviewgrade,
14945
16002
  diffsessionrecords,
@@ -14952,6 +16009,7 @@ export {
14952
16009
  downloadreport,
14953
16010
  draftplan,
14954
16011
  drainqueue,
16012
+ dropimportof,
14955
16013
  dryrunprojection,
14956
16014
  dryrunreport,
14957
16015
  dryrunworkflow,
@@ -15010,8 +16068,11 @@ export {
15010
16068
  expiretokens,
15011
16069
  expirnotes,
15012
16070
  exportcontentreview,
16071
+ exportdatagrid,
15013
16072
  exportlogchain,
16073
+ exportmenudescriptors,
15014
16074
  exportpresetlibrary,
16075
+ exportrowsof,
15015
16076
  exportrunstate,
15016
16077
  exportsessionfile,
15017
16078
  exportworkflow,
@@ -15023,13 +16084,18 @@ export {
15023
16084
  failureclass,
15024
16085
  fallbackroute,
15025
16086
  familyofkind,
16087
+ featuretourordered,
16088
+ featuretourstopat,
16089
+ featuretourstops,
15026
16090
  fetchoptionsof,
15027
16091
  fetchrequestof,
15028
16092
  fieldshapekind,
15029
16093
  fieldshaperegions,
16094
+ filterdatagridrows,
15030
16095
  filteredsessions,
15031
16096
  filterentries,
15032
16097
  filterexchanges,
16098
+ filterlogstream,
15033
16099
  finishrecording,
15034
16100
  fixedheadermatch,
15035
16101
  flowmetricnames,
@@ -15053,6 +16119,11 @@ export {
15053
16119
  growthtrend,
15054
16120
  guardoutput,
15055
16121
  guardverdictgate,
16122
+ guidedtipdismiss,
16123
+ guidedtiprecall,
16124
+ guidedtips,
16125
+ halocolorof,
16126
+ haloof,
15056
16127
  haltedstepsof,
15057
16128
  handleframe,
15058
16129
  handoffframe,
@@ -15077,13 +16148,18 @@ export {
15077
16148
  imagefilterof,
15078
16149
  imagematches,
15079
16150
  imagenames,
16151
+ importexportgate,
16152
+ importexportpayloadof,
16153
+ importexportvalidate,
15080
16154
  importpresetlibrary,
15081
16155
  importsessionfile,
15082
16156
  importworkflow,
16157
+ infercolumntype,
15083
16158
  inflightreport,
15084
16159
  inheritconsent,
15085
16160
  initialize,
15086
16161
  inmemoryvault,
16162
+ interfaceviews,
15087
16163
  interleavetimeline,
15088
16164
  iscdpkind,
15089
16165
  iscontrolflowkind,
@@ -15123,18 +16199,28 @@ export {
15123
16199
  listdue,
15124
16200
  listremotestatus,
15125
16201
  listtools,
16202
+ livebufferof,
15126
16203
  loadworkflow,
16204
+ localebundles,
16205
+ localeformat,
16206
+ localestring,
15127
16207
  localhostbind,
15128
16208
  localsensitivegrade,
15129
16209
  locationconsentcovers,
15130
16210
  locationconsentgate,
15131
16211
  locationpresetof,
15132
16212
  locationrangevalid,
16213
+ lockcandidate,
15133
16214
  lockkey,
16215
+ logbufferboundvalid,
15134
16216
  logchainreport,
15135
16217
  logentryof,
16218
+ loglevelof,
15136
16219
  loglevels,
15137
16220
  logreadgate,
16221
+ logstreamegressgate,
16222
+ logstreameventof,
16223
+ logstreamgenesis,
15138
16224
  longtaskcapture,
15139
16225
  lookalikedistance,
15140
16226
  loopof,
@@ -15147,6 +16233,7 @@ export {
15147
16233
  markpending,
15148
16234
  markprovider,
15149
16235
  markuprenderstep,
16236
+ maskedvalueof,
15150
16237
  maskexport,
15151
16238
  maskfield,
15152
16239
  maskformstate,
@@ -15157,6 +16244,7 @@ export {
15157
16244
  maskstoredvalues,
15158
16245
  masktypedvalues,
15159
16246
  maskvalue,
16247
+ maskverdictsof,
15160
16248
  matchingcorrections,
15161
16249
  matchmessage,
15162
16250
  matchurl,
@@ -15204,6 +16292,10 @@ export {
15204
16292
  normalizeendpoint,
15205
16293
  notebodyof,
15206
16294
  notehistoryentry,
16295
+ notificationcontentgate,
16296
+ notificationrespectsdnd,
16297
+ notifyattentionof,
16298
+ notifydoneof,
15207
16299
  oauthflowof,
15208
16300
  observationmodeof,
15209
16301
  observationresponse,
@@ -15211,6 +16303,12 @@ export {
15211
16303
  offfamilyof,
15212
16304
  offloadkinds,
15213
16305
  offscreencapabilitygate,
16306
+ omniboxtaskgate,
16307
+ omniboxtasktotaskinput,
16308
+ onboardingcomplete,
16309
+ onboardingconsentgate,
16310
+ onboardingstart,
16311
+ onboardingsteps,
15214
16312
  openchannel,
15215
16313
  openconsensus,
15216
16314
  openconsentwindow,
@@ -15228,21 +16326,30 @@ export {
15228
16326
  originprofilegate,
15229
16327
  originprofileof,
15230
16328
  outcomeresponse,
16329
+ overlayslider,
15231
16330
  overrideinputof,
15232
16331
  overridematches,
16332
+ pagechipof,
16333
+ pagechipresolve,
15233
16334
  pairclient,
15234
16335
  pairexchange,
15235
16336
  pairingframes,
15236
16337
  pairstates,
16338
+ paletteactiongate,
15237
16339
  palettecategories,
16340
+ palettecommandsof,
15238
16341
  palettenodes,
16342
+ palettequery,
16343
+ paletteuseafter,
15239
16344
  parallelof,
15240
16345
  parsecommand,
15241
16346
  parsecompletion,
15242
16347
  parseframe,
15243
16348
  parsehtmlbody,
16349
+ parseomniboxtask,
15244
16350
  parseoutput,
15245
16351
  parseproposal,
16352
+ parseshortcut,
15246
16353
  parsessetext,
15247
16354
  parsestream,
15248
16355
  parsetokens,
@@ -15275,11 +16382,17 @@ export {
15275
16382
  phishthresholdgate,
15276
16383
  phishthresholdvalid,
15277
16384
  phishverdictof,
16385
+ pickercandidateof,
16386
+ pickeroverlaygate,
16387
+ pickersessionstart,
15278
16388
  ping,
15279
16389
  planallowlist,
16390
+ plancardgroups,
16391
+ plancardsof,
15280
16392
  plandraftreviewgate,
15281
16393
  planlint,
15282
16394
  plannersplit,
16395
+ planreviewgate,
15283
16396
  pollcursorof,
15284
16397
  polldecision,
15285
16398
  pollurl,
@@ -15313,8 +16426,12 @@ export {
15313
16426
  queuecomplete,
15314
16427
  queuefire,
15315
16428
  queuelanesvalid,
16429
+ quickactioncatalog,
16430
+ quickactiongate,
16431
+ quickactionsfor,
15316
16432
  randomid,
15317
16433
  rankapis,
16434
+ rankcandidates,
15318
16435
  rankrecall,
15319
16436
  ratelimitboundsvalid,
15320
16437
  ratelimitbudgetallowed,
@@ -15330,6 +16447,9 @@ export {
15330
16447
  recallentryof,
15331
16448
  receivemessage,
15332
16449
  receivemessages,
16450
+ recenttrayactions,
16451
+ recenttrayafter,
16452
+ recenttrayentryof,
15333
16453
  reconnectwaits,
15334
16454
  recordagentusage,
15335
16455
  recordenvironment,
@@ -15380,7 +16500,10 @@ export {
15380
16500
  requestreview,
15381
16501
  requeue,
15382
16502
  requireapproval,
16503
+ resolutionhistoryafter,
16504
+ resolutionlogeventof,
15383
16505
  resolutionverdict,
16506
+ resolveappearance,
15384
16507
  resolveapproval,
15385
16508
  resolvedrisk,
15386
16509
  resolveescalation,
@@ -15483,6 +16606,7 @@ export {
15483
16606
  securityreport,
15484
16607
  seededrandom,
15485
16608
  selectorresponse,
16609
+ selectrowrange,
15486
16610
  semanticrecallscopegate,
15487
16611
  sendcdpcommand,
15488
16612
  sendfetch,
@@ -15516,32 +16640,55 @@ export {
15516
16640
  sharelesson,
15517
16641
  shareworkflow,
15518
16642
  shiftentryof,
16643
+ shortcutbindingafter,
16644
+ shortcutcommandof,
16645
+ shortcutdefaults,
16646
+ shortcutdispatchable,
16647
+ shortcutkeygate,
16648
+ shortcuttext,
16649
+ shotpanelgate,
16650
+ shotpanelof,
16651
+ shotpanelpan,
16652
+ shotpanelzoom,
15519
16653
  signalsreport,
15520
16654
  sitenoteof,
15521
16655
  sitenotesreadgate,
15522
16656
  sitenoteswritegate,
16657
+ siteprofileactive,
16658
+ siteprofilefor,
16659
+ siteprofilegate,
16660
+ siteprofileof,
15523
16661
  snapnode,
15524
16662
  snapshotplanof,
15525
16663
  snapshotretentionwindow,
15526
16664
  snapshotsections,
15527
16665
  socketgate,
15528
16666
  socketkinds,
16667
+ sortdatagridrows,
15529
16668
  sourcemapconsentcovers,
15530
16669
  spamdetect,
15531
16670
  spamruleof,
15532
16671
  spawn,
15533
16672
  spawngrade,
15534
16673
  sserequestheaders,
16674
+ stabilityscoreof,
15535
16675
  stackedcount,
15536
16676
  stackframes,
15537
16677
  stackgate,
15538
16678
  starttls,
16679
+ statusbadgeof,
15539
16680
  statusclassof,
15540
16681
  steal,
16682
+ stepapprovegate,
15541
16683
  stepenvironmentvalid,
15542
16684
  stepmodeof,
16685
+ stepresolutionof,
16686
+ stepstimelinenodes,
15543
16687
  steptemplateof,
15544
16688
  stepwindows,
16689
+ stetoasthistory,
16690
+ stetoastof,
16691
+ stetoaststackafter,
15545
16692
  stopone,
15546
16693
  streamchunkframe,
15547
16694
  streamdelta,
@@ -15557,6 +16704,9 @@ export {
15557
16704
  summaryhistoryentry,
15558
16705
  summaryrequestof,
15559
16706
  summarywindowvalid,
16707
+ supportedlanguages,
16708
+ surfacepalette,
16709
+ surfacesnapshot,
15560
16710
  swarmcosts,
15561
16711
  swarmoverview,
15562
16712
  swarmreport,
@@ -15568,6 +16718,9 @@ export {
15568
16718
  tabsessionrefof,
15569
16719
  targetgate,
15570
16720
  taskcounts,
16721
+ taskhistoryafter,
16722
+ taskinputof,
16723
+ taskinputproposalgate,
15571
16724
  taskstatechecksum,
15572
16725
  taskstateof,
15573
16726
  taskstatevalid,
@@ -15658,6 +16811,7 @@ export {
15658
16811
  verdictfresh,
15659
16812
  verifyauth,
15660
16813
  verifylogchain,
16814
+ verifylogstream,
15661
16815
  verifytoken,
15662
16816
  verifywebhook,
15663
16817
  visitmatch,