lazycodex-ai 5.0.0-beta.82 → 5.0.0-beta.83

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 (104) hide show
  1. package/README.ja.md +2 -2
  2. package/README.ko.md +2 -2
  3. package/README.md +4 -4
  4. package/README.ru.md +2 -2
  5. package/README.zh-cn.md +2 -2
  6. package/dist/cli/index.js +392 -112
  7. package/dist/cli/install-native/index.d.ts +4 -0
  8. package/dist/cli/install-native/plan.d.ts +11 -0
  9. package/dist/cli/install-native/run-native-install.d.ts +23 -0
  10. package/dist/cli/install-native-dev/index.d.ts +4 -0
  11. package/dist/cli/native-dev-platform-flag.d.ts +5 -0
  12. package/dist/cli/native-edition-hint.d.ts +10 -0
  13. package/dist/cli/types.d.ts +3 -2
  14. package/dist/cli-node/index.js +392 -112
  15. package/package.json +1 -1
  16. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  17. package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +84 -11
  18. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  19. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  20. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  21. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  22. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  23. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  24. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  25. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  26. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  27. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  28. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  29. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  30. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  31. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  32. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  33. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  34. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  35. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  36. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  37. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  38. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  39. package/packages/omo-codex/plugin/components/ulw-loop/dist/cli.js +24 -10
  40. package/packages/omo-codex/plugin/components/ulw-loop/dist/spawn-guard.js +8 -6
  41. package/packages/omo-codex/plugin/components/ulw-loop/dist/surface.d.ts +2 -0
  42. package/packages/omo-codex/plugin/components/ulw-loop/dist/surface.js +21 -4
  43. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  44. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  45. package/packages/omo-codex/plugin/components/ulw-loop/src/spawn-guard.ts +10 -5
  46. package/packages/omo-codex/plugin/components/ulw-loop/src/surface.ts +24 -6
  47. package/packages/omo-codex/plugin/components/ulw-loop/test/spawn-guard-native-reviewer.test.ts +207 -0
  48. package/packages/omo-codex/plugin/components/ulw-loop/test/spawn-guard.test.ts +6 -4
  49. package/packages/omo-codex/plugin/components/ulw-loop/test/surface.test.ts +43 -4
  50. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  51. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  52. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  53. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  54. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  55. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  56. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  57. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  58. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  59. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  60. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  61. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  62. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  63. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  64. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  65. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  66. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  67. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  68. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  69. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  70. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  71. package/packages/omo-codex/plugin/package-lock.json +12 -12
  72. package/packages/omo-codex/plugin/package.json +1 -1
  73. package/packages/omo-codex/plugin/skills/browser/ATTRIBUTION.md +25 -0
  74. package/packages/omo-codex/plugin/skills/browser/SKILL.md +89 -0
  75. package/packages/omo-codex/plugin/skills/browser/agents/openai.yaml +2 -0
  76. package/packages/omo-codex/plugin/skills/browser/references/commands.md +90 -0
  77. package/packages/omo-codex/plugin/skills/browser/references/install.md +71 -0
  78. package/packages/omo-codex/plugin/skills/browser/references/owned-engine/README.md +42 -0
  79. package/packages/omo-codex/plugin/skills/browser/references/owned-engine/frames-and-humans.md +39 -0
  80. package/packages/omo-codex/plugin/skills/browser/references/owned-engine/ladder.md +59 -0
  81. package/packages/omo-codex/plugin/skills/browser/references/owned-engine/network.md +42 -0
  82. package/packages/omo-codex/plugin/skills/browser/references/recipes/1password.md +59 -0
  83. package/packages/omo-codex/plugin/skills/browser/references/remote.md +24 -0
  84. package/packages/omo-codex/plugin/skills/browser/scripts/browser-doctor.mjs +41 -0
  85. package/packages/omo-codex/plugin/skills/browser/scripts/browser-env.mjs +41 -0
  86. package/packages/omo-codex/plugin/skills/browser/scripts/browser-install.mjs +51 -0
  87. package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +1 -0
  88. package/packages/omo-codex/scripts/install-dist/install-local.mjs +90 -17
  89. package/packages/shared-skills/skills/browser/ATTRIBUTION.md +25 -0
  90. package/packages/shared-skills/skills/browser/SKILL.md +89 -0
  91. package/packages/shared-skills/skills/browser/references/commands.md +90 -0
  92. package/packages/shared-skills/skills/browser/references/install.md +71 -0
  93. package/packages/shared-skills/skills/browser/references/owned-engine/README.md +42 -0
  94. package/packages/shared-skills/skills/browser/references/owned-engine/frames-and-humans.md +39 -0
  95. package/packages/shared-skills/skills/browser/references/owned-engine/ladder.md +59 -0
  96. package/packages/shared-skills/skills/browser/references/owned-engine/network.md +42 -0
  97. package/packages/shared-skills/skills/browser/references/recipes/1password.md +59 -0
  98. package/packages/shared-skills/skills/browser/references/remote.md +24 -0
  99. package/packages/shared-skills/skills/browser/scripts/browser-doctor.mjs +41 -0
  100. package/packages/shared-skills/skills/browser/scripts/browser-env.mjs +41 -0
  101. package/packages/shared-skills/skills/browser/scripts/browser-install.mjs +51 -0
  102. package/dist/cli/install-senpi/index.d.ts +0 -1
  103. package/dist/cli/senpi-edition-hint.d.ts +0 -10
  104. package/dist/cli/senpi-platform-flag.d.ts +0 -4
@@ -0,0 +1,24 @@
1
+ # Agent here, browser there
2
+
3
+ The agent and the browser do not have to be the same machine. Upstream supports this directly;
4
+ nothing in this package needs to bridge it.
5
+
6
+ Shape:
7
+
8
+ - The **browser machine** needs only the extension.
9
+ - The **agent machine** runs the `bsk` CLI and this skill.
10
+ - They are joined by a daemon in server mode plus a pairing link.
11
+
12
+ ```bash
13
+ bsk daemon start --mode server # on the machine the agent runs on
14
+ ```
15
+
16
+ Then follow upstream's pairing guide, which owns the current flag surface and the TLS
17
+ prerequisites: https://github.com/Tencent/BrowserSkill/blob/main/docs/remote-extension-connection.md
18
+
19
+ Once paired, every command in `commands.md` behaves identically; `--out` paths still resolve on
20
+ the machine that ran the command.
21
+
22
+ If pairing is not configured, say so and ask. Do not substitute a browser on the agent machine:
23
+ the point of the attached engine is the sessions that live in the user's browser, and a local
24
+ browser has none of them.
@@ -0,0 +1,41 @@
1
+ #!/usr/bin/env node
2
+ import { platform } from "node:os"
3
+ import { connectedBrowsers, readStatus, resolveCli, STORE_LISTINGS, SUPPORTED_PLATFORMS } from "./browser-env.mjs"
4
+
5
+ const REMEDIES = {
6
+ ready: "Start a session: bsk session start --json --no-focus --name \"<task>\"",
7
+ "no-extension": `Ask the user to install and enable the extension, then re-run this doctor.\n Chrome: ${STORE_LISTINGS.chrome}\n Edge: ${STORE_LISTINGS.edge}`,
8
+ "no-cli": "Install the CLI: node \"<skill-root>/scripts/browser-install.mjs\", then re-run this doctor.",
9
+ "no-browser-support": "This platform has no supported browser. Say so and stop; do not substitute another engine.",
10
+ }
11
+
12
+ async function diagnose() {
13
+ if (!SUPPORTED_PLATFORMS.has(platform())) {
14
+ return { state: "no-browser-support", platform: platform() }
15
+ }
16
+ const cli = await resolveCli()
17
+ if (cli === undefined) return { state: "no-cli", platform: platform() }
18
+
19
+ let status
20
+ try {
21
+ status = await readStatus(cli)
22
+ } catch (error) {
23
+ return { state: "no-extension", platform: platform(), cli, detail: `status failed: ${error.message}` }
24
+ }
25
+ const browsers = connectedBrowsers(status)
26
+ if (browsers.length === 0) return { state: "no-extension", platform: platform(), cli }
27
+ return { state: "ready", platform: platform(), cli, browsers: browsers.length }
28
+ }
29
+
30
+ const report = await diagnose()
31
+ const json = process.argv.includes("--json")
32
+ if (json) {
33
+ console.log(JSON.stringify({ ...report, remedy: REMEDIES[report.state] }, null, 2))
34
+ } else {
35
+ console.log(`state: ${report.state}`)
36
+ if (report.cli) console.log(`cli: ${report.cli}`)
37
+ if (report.browsers) console.log(`browsers connected: ${report.browsers}`)
38
+ if (report.detail) console.log(`detail: ${report.detail}`)
39
+ console.log(`\n${REMEDIES[report.state]}`)
40
+ }
41
+ process.exit(report.state === "ready" ? 0 : 1)
@@ -0,0 +1,41 @@
1
+ import { execFile } from "node:child_process"
2
+ import { existsSync } from "node:fs"
3
+ import { homedir, platform } from "node:os"
4
+ import { join } from "node:path"
5
+ import { promisify } from "node:util"
6
+
7
+ const run = promisify(execFile)
8
+
9
+ export const STORE_LISTINGS = {
10
+ chrome: "https://chromewebstore.google.com/detail/hhcmgoofomhgciiibhipgmgkgnoenaoi",
11
+ edge: "https://microsoftedge.microsoft.com/addons/detail/browserskill/emacgiaaaiojkkpkddmmdfhmokgmnikg",
12
+ }
13
+
14
+ export const SUPPORTED_PLATFORMS = new Set(["darwin", "linux", "win32"])
15
+
16
+ export function localBinCandidates() {
17
+ const bin = join(homedir(), ".local", "bin")
18
+ return platform() === "win32" ? [join(bin, "bsk.exe"), join(bin, "bsk")] : [join(bin, "bsk")]
19
+ }
20
+
21
+ export async function resolveCli() {
22
+ for (const candidate of localBinCandidates()) {
23
+ if (existsSync(candidate)) return candidate
24
+ }
25
+ try {
26
+ await run("bsk", ["--version"], { timeout: 15000, windowsHide: true })
27
+ return "bsk"
28
+ } catch {
29
+ return undefined
30
+ }
31
+ }
32
+
33
+ export async function readStatus(cli) {
34
+ const { stdout } = await run(cli, ["status", "--json"], { timeout: 30000, windowsHide: true })
35
+ return JSON.parse(stdout)
36
+ }
37
+
38
+ export function connectedBrowsers(status) {
39
+ const browsers = status?.browsers
40
+ return Array.isArray(browsers) ? browsers : []
41
+ }
@@ -0,0 +1,51 @@
1
+ #!/usr/bin/env node
2
+ import { spawn } from "node:child_process"
3
+ import { platform } from "node:os"
4
+ import { resolveCli, STORE_LISTINGS, SUPPORTED_PLATFORMS } from "./browser-env.mjs"
5
+
6
+ const UNIX_INSTALL = "curl -fsSL https://raw.githubusercontent.com/Tencent/BrowserSkill/main/install.sh | sh"
7
+ const WINDOWS_INSTALL = "irm https://raw.githubusercontent.com/Tencent/BrowserSkill/main/install.ps1 | iex"
8
+
9
+ function installCommand() {
10
+ return platform() === "win32"
11
+ ? { file: "powershell", args: ["-NoProfile", "-Command", WINDOWS_INSTALL], display: WINDOWS_INSTALL }
12
+ : { file: "sh", args: ["-c", UNIX_INSTALL], display: UNIX_INSTALL }
13
+ }
14
+
15
+ function spawnInstaller({ file, args }) {
16
+ return new Promise((resolve) => {
17
+ const child = spawn(file, args, { stdio: "inherit", windowsHide: true })
18
+ child.on("error", () => resolve(1))
19
+ child.on("close", (code) => resolve(code ?? 1))
20
+ })
21
+ }
22
+
23
+ if (!SUPPORTED_PLATFORMS.has(platform())) {
24
+ console.error(`unsupported platform: ${platform()}. macOS, Linux and Windows x64 only.`)
25
+ process.exit(1)
26
+ }
27
+
28
+ if (await resolveCli()) {
29
+ console.log("bsk is already installed; run browser-doctor.mjs to check the extension.")
30
+ process.exit(0)
31
+ }
32
+
33
+ const command = installCommand()
34
+ console.log(`installing the bsk CLI with the upstream installer:\n ${command.display}\n`)
35
+ const code = await spawnInstaller(command)
36
+ if (code !== 0) {
37
+ console.error(`\ninstaller exited ${code}. Report this instead of retrying blindly.`)
38
+ process.exit(code)
39
+ }
40
+
41
+ console.log([
42
+ "",
43
+ "CLI installed. Two things remain, and only the user can do the first:",
44
+ "",
45
+ "1. Install the browser extension from the store, then enable it:",
46
+ ` Chrome: ${STORE_LISTINGS.chrome}`,
47
+ ` Edge: ${STORE_LISTINGS.edge}`,
48
+ "2. Re-run: node \"<skill-root>/scripts/browser-doctor.mjs\"",
49
+ "",
50
+ "If PATH does not pick up the CLI in this shell, use its absolute path under ~/.local/bin.",
51
+ ].join("\n"))
@@ -6,6 +6,7 @@ export const CONTEXT_PRESSURE_SKILL_BUDGET_BYTES = 25_000;
6
6
 
7
7
  export const expectedSkills = [
8
8
  "ast-grep",
9
+ "browser",
9
10
  "coding-agent-sessions",
10
11
  "comment-checker",
11
12
  "data-scientist",
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // omo-codex-install:6df5dbbbb7ca9b9dce86fae98a525a9caa7de96caed85a4b77d4e8b4ab4d1501:4c50a551b52c74c82521d2fcbd9c9a1db21370470eb76a3195db19bdfcbad5b1
2
+ // omo-codex-install:88ab1eaf77d9f58468ed3f04e9c7d6c7dbb32d7c87feee69f45401431352184f:6f7e0588dc9a653cf42c9b4466272eea05e8c081bc8dc62082c03c1e5562cc31
3
3
  var __esm = (fn, res, err) => () => {
4
4
  if (fn)
5
5
  try {
@@ -316,7 +316,7 @@ function shouldRetainLine(line, cutoffMs) {
316
316
  function parseDiagnosticLine(line) {
317
317
  try {
318
318
  const parsed = JSON.parse(line);
319
- if (!isRecord9(parsed)) {
319
+ if (!isRecord10(parsed)) {
320
320
  return null;
321
321
  }
322
322
  return parsed;
@@ -327,7 +327,7 @@ function parseDiagnosticLine(line) {
327
327
  throw error;
328
328
  }
329
329
  }
330
- function isRecord9(value) {
330
+ function isRecord10(value) {
331
331
  return value !== null && typeof value === "object" && !Array.isArray(value);
332
332
  }
333
333
  function trimToMaxBytes(lines) {
@@ -7817,7 +7817,7 @@ function coerceBool(value) {
7817
7817
  function coerceString(value) {
7818
7818
  return typeof value == "string" ? value : undefined;
7819
7819
  }
7820
- function isRecord10(value) {
7820
+ function isRecord11(value) {
7821
7821
  return typeof value == "object" && value !== null && !Array.isArray(value);
7822
7822
  }
7823
7823
  function toRfc3339(timestamp) {
@@ -7839,7 +7839,7 @@ function relocateInto(properties, key, value) {
7839
7839
  properties[key] = value;
7840
7840
  }
7841
7841
  function buildV1Event(message) {
7842
- const sourceProperties = isRecord10(message.properties) ? message.properties : {};
7842
+ const sourceProperties = isRecord11(message.properties) ? message.properties : {};
7843
7843
  const properties = {
7844
7844
  ...sourceProperties
7845
7845
  };
@@ -9984,7 +9984,7 @@ var package_default;
9984
9984
  var init_package = __esm(() => {
9985
9985
  package_default = {
9986
9986
  name: "@oh-my-opencode/omo-codex",
9987
- version: "5.0.0-beta.82",
9987
+ version: "5.0.0-beta.83",
9988
9988
  type: "module",
9989
9989
  private: true,
9990
9990
  description: "Codex harness adapter for oh-my-openagent. Vendored Codex plugin namespace (omo) + TypeScript installer + telemetry.",
@@ -16515,8 +16515,10 @@ var OmoGitMasterSettingsSchema = OmoGitMasterSettingsLayerSchema.extend({
16515
16515
 
16516
16516
  // packages/omo-config-core/src/schema/harness.ts
16517
16517
  var HARNESS_IDS = ["codex", "opencode", "omo"];
16518
- var OMO_CONFIG_HARNESS_IDS = ["opencode", "senpi", "codex"];
16518
+ var OMO_CONFIG_HARNESS_IDS = ["opencode", "native", "codex"];
16519
16519
  var OmoHarnessIdSchema = _enum(OMO_CONFIG_HARNESS_IDS);
16520
+ var OMO_CONFIG_LEGACY_HARNESS_ALIASES = { senpi: "native" };
16521
+ var OMO_CONFIG_LEGACY_HARNESS_IDS = Object.keys(OMO_CONFIG_LEGACY_HARNESS_ALIASES);
16520
16522
 
16521
16523
  // packages/omo-config-core/src/schema/memory.ts
16522
16524
  var OmoMemoryReflectionTriggerSchema = object({
@@ -16975,6 +16977,7 @@ var OmoConfigProfileSchema = object({
16975
16977
  telemetry: OmoTelemetrySettingsLayerSchema.optional(),
16976
16978
  disabled_skills: OmoDisabledSkillsSchema.optional(),
16977
16979
  "[opencode]": OmoOpenCodeHarnessConfigSchema.optional(),
16980
+ "[native]": OmoTypedHarnessConfigSchema.optional(),
16978
16981
  "[senpi]": OmoTypedHarnessConfigSchema.optional(),
16979
16982
  "[codex]": OmoTypedHarnessConfigSchema.optional()
16980
16983
  }).strict();
@@ -16993,6 +16996,7 @@ var OmoConfigSchema = object({
16993
16996
  telemetry: OmoTelemetrySettingsSchema.optional(),
16994
16997
  disabled_skills: OmoDisabledSkillsSchema.optional(),
16995
16998
  "[opencode]": OmoOpenCodeHarnessConfigSchema.optional(),
16999
+ "[native]": OmoTypedHarnessConfigSchema.optional(),
16996
17000
  "[senpi]": OmoTypedHarnessConfigSchema.optional(),
16997
17001
  "[codex]": OmoTypedHarnessConfigSchema.optional(),
16998
17002
  profiles: record(string2(), OmoConfigProfileSchema).default({}),
@@ -17014,6 +17018,7 @@ var OmoConfigLayerSchema = object({
17014
17018
  telemetry: OmoTelemetrySettingsLayerSchema.optional(),
17015
17019
  disabled_skills: OmoDisabledSkillsSchema.optional(),
17016
17020
  "[opencode]": OmoOpenCodeHarnessConfigSchema.optional(),
17021
+ "[native]": OmoTypedHarnessConfigSchema.optional(),
17017
17022
  "[senpi]": OmoTypedHarnessConfigSchema.optional(),
17018
17023
  "[codex]": OmoTypedHarnessConfigSchema.optional(),
17019
17024
  profiles: record(string2(), OmoConfigProfileSchema).optional(),
@@ -17077,6 +17082,54 @@ function canonicalizeLegacyCategoryNames(document) {
17077
17082
  return { document: canonicalized, renames };
17078
17083
  }
17079
17084
 
17085
+ // packages/omo-config-core/src/schema/legacy-harness-names.ts
17086
+ function canonicalHarnessName(name) {
17087
+ return Object.hasOwn(OMO_CONFIG_LEGACY_HARNESS_ALIASES, name) ? OMO_CONFIG_LEGACY_HARNESS_ALIASES[name] : name;
17088
+ }
17089
+ function harnessBlockKey(harness) {
17090
+ return `[${harness}]`;
17091
+ }
17092
+ function legacyHarnessOfBlockKey(key) {
17093
+ if (!key.startsWith("[") || !key.endsWith("]"))
17094
+ return;
17095
+ const harness = key.slice(1, -1);
17096
+ return Object.hasOwn(OMO_CONFIG_LEGACY_HARNESS_ALIASES, harness) ? harness : undefined;
17097
+ }
17098
+ function isRecord7(value) {
17099
+ return typeof value === "object" && value !== null && !Array.isArray(value);
17100
+ }
17101
+ function canonicalizeBlocksIn(container, path, renames) {
17102
+ const result = {};
17103
+ for (const [key, value] of Object.entries(container)) {
17104
+ const legacyHarness = legacyHarnessOfBlockKey(key);
17105
+ if (legacyHarness === undefined) {
17106
+ result[key] = value;
17107
+ continue;
17108
+ }
17109
+ const canonical = harnessBlockKey(canonicalHarnessName(legacyHarness));
17110
+ const dropped = Object.hasOwn(container, canonical);
17111
+ renames.push({ canonical, dropped, legacy: key, path: [...path, key].join(".") });
17112
+ if (!dropped)
17113
+ result[canonical] = value;
17114
+ }
17115
+ return result;
17116
+ }
17117
+ function canonicalizeLegacyHarnessBlocks(document) {
17118
+ if (!isRecord7(document))
17119
+ return { document: {}, renames: [] };
17120
+ const renames = [];
17121
+ const canonicalized = canonicalizeBlocksIn(document, [], renames);
17122
+ const profiles = canonicalized["profiles"];
17123
+ if (isRecord7(profiles)) {
17124
+ const canonicalProfiles = {};
17125
+ for (const [name, profile] of Object.entries(profiles)) {
17126
+ canonicalProfiles[name] = isRecord7(profile) ? canonicalizeBlocksIn(profile, ["profiles", name], renames) : profile;
17127
+ }
17128
+ canonicalized["profiles"] = canonicalProfiles;
17129
+ }
17130
+ return { document: canonicalized, renames };
17131
+ }
17132
+
17080
17133
  // node_modules/.bun/jsonc-parser@3.3.1/node_modules/jsonc-parser/lib/esm/impl/scanner.js
17081
17134
  function createScanner(text, ignoreTrivia = false) {
17082
17135
  const len = text.length;
@@ -18052,7 +18105,7 @@ function resolveOmoConfigPaths(options) {
18052
18105
  }
18053
18106
 
18054
18107
  // packages/omo-config-core/src/loader/resolution.ts
18055
- var HARNESS_KEYS = [...new Set([...HARNESS_IDS, ...OMO_CONFIG_HARNESS_IDS])].map((harness) => `[${harness}]`);
18108
+ var HARNESS_KEYS = [...new Set([...HARNESS_IDS, ...OMO_CONFIG_HARNESS_IDS, ...OMO_CONFIG_LEGACY_HARNESS_IDS])].map((harness) => harnessBlockKey(harness));
18056
18109
  function profileName(value) {
18057
18110
  return value === "" ? undefined : value;
18058
18111
  }
@@ -18081,7 +18134,13 @@ function withoutControlKeys(config) {
18081
18134
  function harnessLayer(config, harness) {
18082
18135
  if (harness === undefined)
18083
18136
  return {};
18084
- return toRecord(config[`[${harness}]`]) ?? {};
18137
+ const canonical = canonicalHarnessName(harness);
18138
+ const legacyKeys = Object.entries(OMO_CONFIG_LEGACY_HARNESS_ALIASES).filter(([, target]) => target === canonical).map(([legacy]) => harnessBlockKey(legacy));
18139
+ let layer = {};
18140
+ for (const key of [...legacyKeys, harnessBlockKey(canonical)]) {
18141
+ layer = mergeOmoConfigRecords(layer, toRecord(config[key]) ?? {});
18142
+ }
18143
+ return layer;
18085
18144
  }
18086
18145
  function resolveOmoConfigView(options) {
18087
18146
  const profiles = toRecord(options.config["profiles"]);
@@ -18132,6 +18191,7 @@ var DEFAULT_RAW_CONFIG = {
18132
18191
  function stripResolutionControlKeys(config) {
18133
18192
  const {
18134
18193
  "[codex]": _codex,
18194
+ "[native]": _native,
18135
18195
  "[opencode]": _opencode,
18136
18196
  "[senpi]": _senpi,
18137
18197
  profiles: _profiles,
@@ -18157,21 +18217,21 @@ function hasUnsafeUnrecognizedKey(issues) {
18157
18217
  function hasTamperedPrototype(value) {
18158
18218
  if (Array.isArray(value))
18159
18219
  return value.some((entry) => hasTamperedPrototype(entry));
18160
- if (!isRecord7(value))
18220
+ if (!isRecord8(value))
18161
18221
  return false;
18162
18222
  const prototype = Object.getPrototypeOf(value);
18163
18223
  if (prototype !== Object.prototype && prototype !== null)
18164
18224
  return true;
18165
18225
  return Object.values(value).some((entry) => hasTamperedPrototype(entry));
18166
18226
  }
18167
- function isRecord7(value) {
18227
+ function isRecord8(value) {
18168
18228
  return typeof value === "object" && value !== null && !Array.isArray(value);
18169
18229
  }
18170
18230
  function containerAt(record, path) {
18171
18231
  let container = record;
18172
18232
  for (const segment of path) {
18173
18233
  const next = container[segment];
18174
- if (!isRecord7(next))
18234
+ if (!isRecord8(next))
18175
18235
  return null;
18176
18236
  container = next;
18177
18237
  }
@@ -18282,6 +18342,15 @@ function legacyCategoryDiagnostic(path, renames) {
18282
18342
  issuePaths: renames.map((rename) => rename.path)
18283
18343
  };
18284
18344
  }
18345
+ function legacyHarnessDiagnostic(path, renames) {
18346
+ const detail = renames.map((rename) => rename.dropped ? `${rename.path} ignored because ${rename.canonical} is also configured` : `${rename.path} renamed to ${rename.canonical}`).join(", ");
18347
+ return {
18348
+ kind: "deprecated-keys",
18349
+ message: `Deprecated harness block in ${path}: ${detail}. Rename it; the alias is removed in a future release.`,
18350
+ path,
18351
+ issuePaths: renames.map((rename) => rename.path)
18352
+ };
18353
+ }
18285
18354
  function loadOmoConfig(options = {}) {
18286
18355
  const fileSystem = options.fileSystem ?? DEFAULT_READ_FILE_SYSTEM;
18287
18356
  const cwd = options.cwd ?? process.cwd();
@@ -18304,8 +18373,12 @@ function loadOmoConfig(options = {}) {
18304
18373
  if (canonicalized.renames.length > 0) {
18305
18374
  diagnostics.push(legacyCategoryDiagnostic(candidate.path, canonicalized.renames));
18306
18375
  }
18307
- layers.push({ config: canonicalized.document, source: loaded.source });
18308
- merged = mergeOmoConfigRecords(merged, canonicalized.document);
18376
+ const harnessCanonicalized = canonicalizeLegacyHarnessBlocks(canonicalized.document);
18377
+ if (harnessCanonicalized.renames.length > 0) {
18378
+ diagnostics.push(legacyHarnessDiagnostic(candidate.path, harnessCanonicalized.renames));
18379
+ }
18380
+ layers.push({ config: harnessCanonicalized.document, source: loaded.source });
18381
+ merged = mergeOmoConfigRecords(merged, harnessCanonicalized.document);
18309
18382
  }
18310
18383
  }
18311
18384
  const requestedProfile = resolveOmoProfileName({
@@ -20905,10 +20978,10 @@ function readCatalogMultiAgentVersion(model, cachePath) {
20905
20978
  } catch {
20906
20979
  return null;
20907
20980
  }
20908
- if (!isRecord8(cache) || !Array.isArray(cache.models))
20981
+ if (!isRecord9(cache) || !Array.isArray(cache.models))
20909
20982
  return null;
20910
20983
  for (const entry of cache.models) {
20911
- if (!isRecord8(entry))
20984
+ if (!isRecord9(entry))
20912
20985
  continue;
20913
20986
  if (entry.slug !== model && entry.id !== model)
20914
20987
  continue;
@@ -20933,7 +21006,7 @@ function readRootModelCatalogPath(config) {
20933
21006
  const single = config.match(/^\s*model_catalog_json\s*=\s*'([^']+)'/m);
20934
21007
  return single?.[1] ?? null;
20935
21008
  }
20936
- function isRecord8(value) {
21009
+ function isRecord9(value) {
20937
21010
  return typeof value === "object" && value !== null && !Array.isArray(value);
20938
21011
  }
20939
21012
  function removeFeatureFlagSetting(config, featureName) {
@@ -0,0 +1,25 @@
1
+ # ATTRIBUTION / NOTICE
2
+
3
+ This skill (`browser`, part of `@oh-my-opencode/shared-skills`) is project-original documentation.
4
+ It drives a third-party tool that it does **not** redistribute.
5
+
6
+ ## BrowserSkill — driven, not vendored
7
+
8
+ The attached engine this skill documents is **BrowserSkill** by Tencent.
9
+
10
+ - Upstream: https://github.com/Tencent/BrowserSkill
11
+ - License: MIT
12
+ - What ships here: documentation and two local helper scripts, authored by this project.
13
+ - What does NOT ship here: the `bsk` CLI, the daemon, the browser extension, or any upstream
14
+ source. The user installs those from upstream's own installer and from the Chrome Web Store /
15
+ Edge Add-ons listings. This package never bundles a browser binary or an extension payload.
16
+
17
+ MIT permits redistribution; we simply have no reason to, because upstream publishes signed
18
+ per-platform releases and store builds that stay current on their own.
19
+
20
+ ## Owned-engine references
21
+
22
+ `references/owned-engine/` documents a *contract* for a code-driven browser — the escalation
23
+ ladder, viewport pinning, reading the network instead of the DOM, overlay and cross-origin
24
+ handling — not any particular package. The techniques are generic CDP practice. No third-party
25
+ source is reproduced.
@@ -0,0 +1,89 @@
1
+ ---
2
+ name: browser
3
+ description: "Drives a real browser: sites the user is already signed into, forms and clicks, JS-rendered pages, screenshots, web QA, extension popups, and a human handoff for login, CAPTCHA or OTP. Works through the BrowserSkill extension and its bsk CLI, inside the user's own browser, in a separate Agent Window. Use for any interactive browser task; not for a plain search or an unblocked static fetch."
4
+ ---
5
+
6
+ # Browser
7
+
8
+ Two engines live behind this skill. Choose before you act:
9
+
10
+ | You need | Engine | Where |
11
+ |---|---|---|
12
+ | A site the user is signed into, a form, a click-through, a screenshot, web QA, an extension popup | **attached** — the user's own browser | this file |
13
+ | A throwaway profile, bot-scoring evasion, a CAPTCHA, network interception, a QA flight trace, coordinate control | **owned** — a browser your code launches | [references/owned-engine/README.md](references/owned-engine/README.md) |
14
+ | Text out of a URL, a 403 bypass, a platform that blocks fetchers | neither | the `ultimate-browsing` skill |
15
+
16
+ **Attached is the default,** because it is the only engine carrying the user's logins and the only
17
+ one where a human is a single command away. The owned engine is an opt-in local install, not part
18
+ of this package.
19
+
20
+ ## Step 0 — prove the stack before you drive it
21
+
22
+ ```bash
23
+ node "<skill-root>/scripts/browser-doctor.mjs"
24
+ ```
25
+
26
+ It reports one of four states and what to do next:
27
+
28
+ | State | Meaning | Next |
29
+ |---|---|---|
30
+ | `ready` | CLI, daemon and a connected browser | start a session |
31
+ | `no-extension` | CLI works, no browser is connected | give the user the store link the doctor printed, wait, re-run |
32
+ | `no-cli` | `bsk` is not installed | `node "<skill-root>/scripts/browser-install.mjs"`, then re-run |
33
+ | `no-browser-support` | the platform has no supported browser | say so and stop |
34
+
35
+ **Never substitute another browser for a missing one.** A headless browser you launch yourself has
36
+ none of the user's sessions, so every login turns into a ladder you should not be climbing. If the
37
+ attached engine is unavailable, say which state you hit and ask the user.
38
+
39
+ ## The loop
40
+
41
+ ```bash
42
+ bsk session start --json --no-focus --name "<task>" # keep session_id
43
+ bsk navigate https://example.com --session <id> --json
44
+ bsk observe --session <id> # @eN refs live here
45
+ bsk click @e1 --session <id> --json
46
+ bsk screenshot --session <id> --out ./shot.png --json
47
+ bsk session stop <id> --json # success AND failure
48
+ ```
49
+
50
+ 1. **Observe before every action.** `observe` returns a semantic tree whose `@eN` refs are reissued
51
+ on each call. Read a ref and use it in the same cycle; a ref from two calls ago points somewhere
52
+ else now.
53
+ 2. **Navigation and large DOM changes stale every ref.** Observe again rather than reusing.
54
+ 3. **Two identical failures mean change approach, not retry.** A third identical attempt is a defect.
55
+ 4. **Borrow a user tab explicitly** (`tab list --scope user`, `tab borrow <id>`, `tab return <id>`).
56
+ Borrowing prompts the user; never invent tab ids and never repeat a denied borrow.
57
+ 5. **Always stop the session,** on success and on failure. Stopping also returns borrowed tabs.
58
+
59
+ Command semantics, the flags that behave differently than they read, and the failure table are in
60
+ [references/commands.md](references/commands.md).
61
+
62
+ ## When a human is the only way through
63
+
64
+ Login, CAPTCHA, OTP, a payment confirmation, a consent dialog:
65
+
66
+ ```bash
67
+ bsk request-help --session <id> --prompt "<what you need done>" [--target @eN]
68
+ ```
69
+
70
+ Then observe again. Respect a `cancelled` or `timed_out` answer; do not work around it by changing
71
+ the extension's automation settings.
72
+
73
+ ## Rules
74
+
75
+ - **Never read credentials through the page.** No `evaluate` that extracts a password, token, cookie
76
+ or recovery code. The value of this engine is that the browser is already signed in.
77
+ - **Never clear cookies, cache or site data.** It is the user's real profile; clearing it logs them
78
+ out everywhere. No flow here needs it.
79
+ - **`--no-focus` by default.** The browser belongs to someone who is probably using it.
80
+ - **One short, named session per task,** always stopped.
81
+ - Do not toggle the extension's automation settings, and do not restart the browser to fix a state.
82
+
83
+ ## More
84
+
85
+ - [references/install.md](references/install.md) — installing the CLI and the extension, per OS
86
+ - [references/commands.md](references/commands.md) — command semantics, refs, failure table
87
+ - [references/remote.md](references/remote.md) — agent on one machine, browser on another
88
+ - [references/recipes/1password.md](references/recipes/1password.md) — reading a vault the user has unlocked
89
+ - [references/owned-engine/README.md](references/owned-engine/README.md) — the code-driven engine
@@ -0,0 +1,90 @@
1
+ # Command semantics
2
+
3
+ Everything here cost a failed attempt to learn. Read it before improvising.
4
+
5
+ ## Sessions
6
+
7
+ ```bash
8
+ bsk session start --json --no-focus --name "<task>" # keep session_id
9
+ bsk session list
10
+ bsk session stop <id> --json # positional id, not --session
11
+ ```
12
+
13
+ Every session-scoped command needs `--session <id>`. `--no-focus` keeps the Agent Window from
14
+ stealing focus; drop it only when the user is watching on purpose.
15
+
16
+ ## Reading
17
+
18
+ | Command | Returns |
19
+ |---|---|
20
+ | `observe --session <id>` | semantic tree with `@eN` refs and perception probes — **the default read** |
21
+ | `snapshot --session <id>` | static accessibility tree |
22
+ | `get-html --session <id>` | exact markup, hidden metadata |
23
+ | `screenshot --session <id> --out <path>` | PNG; add `--full-page` for a long capture |
24
+ | `evaluate "<js>" --session <id> --json` | `{ok, value}` — **check `.ok`; exit code 0 does not mean the script succeeded** |
25
+ | `console` / `network` | buffered log lines and responses |
26
+
27
+ **Refs are reissued by every `observe` and `snapshot`.** Read a ref and act on it in the same
28
+ cycle. A ref captured two calls ago silently addresses a different element — this is how a click
29
+ lands on the neighbouring row.
30
+
31
+ `observe --max-tokens <n>` bounds a large page. There is no default cap.
32
+
33
+ ## Acting
34
+
35
+ | Need | Command |
36
+ |---|---|
37
+ | Click | `click @e3 --session <id>` |
38
+ | Fill | `fill @e3 --value "text" --session <id>` |
39
+ | Select | `select @e3 --value "<option value>" --session <id>` |
40
+ | Key | `press Enter --ref @e3 --session <id>` |
41
+ | Hover | `hover @e3 --session <id>` |
42
+ | Scroll into view | `scroll-to @e3 --session <id>` |
43
+ | Wheel | `wheel --delta-y 600 --session <id>` |
44
+ | Focus / blur | `focus @e3` / `blur @e3` |
45
+ | Upload / download | `upload --file <path>` / `download --out <path>` |
46
+
47
+ Traps:
48
+
49
+ - `select` takes the option's **value attribute**, not its visible label.
50
+ - `fill` and `click` accept a CSS selector; **`press --ref` does not** — it answers
51
+ `ref_not_found` for a selector. `press` without `--ref` goes to the focused node.
52
+ - A menu that a `click` opens can be toggled shut by that same click. `focus` then
53
+ `press Enter` opens it reliably.
54
+ - Hover-only controls report `element not visible`: hover the trigger, observe, then act on the
55
+ revealed item's fresh ref. Markers like `[has-submenu]` and `[expanded]` identify triggers;
56
+ `observe --probe-hover` finds one when no marker does, at the cost of touching the live page.
57
+ - The clipboard is unavailable in a window started `--no-focus` (no document focus), so read
58
+ values out of the DOM instead.
59
+
60
+ ## Borrowing a user tab
61
+
62
+ ```bash
63
+ bsk tab list --scope user
64
+ bsk tab borrow <tab-id>
65
+ bsk tab return <tab-id>
66
+ ```
67
+
68
+ Borrowing asks the user to confirm. Never invent a tab id, never repeat a denied borrow, and
69
+ always return what you borrowed (`session stop` also returns them).
70
+
71
+ ## Failures
72
+
73
+ | Symptom | Meaning | Response |
74
+ |---|---|---|
75
+ | `browsers: []` | extension not connected | ask the user to open the browser / enable the extension |
76
+ | daemon missing | idle exit or reboot | none; the next call restarts it |
77
+ | `cdp_failed: Cannot access a chrome-extension:// URL of different extension` | another extension injected a frame, so the debugger cannot attach to that tab | transient and page-specific; collapse the work into one `evaluate` and retry, or navigate away and back |
78
+ | `permission_denied: element not visible` | hover-gated or clipped control | drive its menu instead |
79
+ | `ref_not_found` | stale ref, or a selector passed to `press` | observe again; use a real ref |
80
+ | version skew warning | CLI and extension disagree | `bsk update` after finishing sessions; the extension updates through its store |
81
+
82
+ **Two identical failures select a different approach. A third identical attempt is a defect.**
83
+
84
+ ## Sandboxed hosts
85
+
86
+ If the host kills background children after each command, the daemon cannot survive between calls.
87
+ Set `BSK_AUTO_START=0`, share one `BSK_HOME` across every call, and start
88
+ `bsk daemon start --foreground` in the host's persistent background task. Check readiness with
89
+ `bsk status --json` in a separate call before continuing. Do not loop on launches, delete runtime
90
+ files, or restart a daemon another task is using.