oh-my-opencode 5.1.26 → 5.1.28

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 (58) hide show
  1. package/dist/cli/index.js +501 -47
  2. package/dist/cli-node/index.js +501 -47
  3. package/dist/index.js +525 -57
  4. package/dist/skills/browser/runtime/omowright/manifest.json +1 -1
  5. package/dist/tui.js +256 -27
  6. package/package.json +14 -14
  7. package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
  8. package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
  9. package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
  10. package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
  11. package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
  12. package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
  13. package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
  14. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
  15. package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
  16. package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
  17. package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
  18. package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
  19. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-5.6.md +1 -1
  20. package/packages/omo-codex/plugin/components/rules/bundled-rules/hephaestus/gpt-6.md +1 -1
  21. package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
  22. package/packages/omo-codex/plugin/components/rules/package.json +1 -1
  23. package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
  24. package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
  25. package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
  26. package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
  27. package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
  28. package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
  29. package/packages/omo-codex/plugin/components/ulw-execute-continuation/hooks/hooks.json +1 -1
  30. package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
  31. package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
  32. package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
  33. package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
  34. package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
  35. package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
  36. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
  37. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
  38. package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
  39. package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
  40. package/packages/omo-codex/plugin/hooks/post-tool-use-recording-spawn-admission.json +1 -1
  41. package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
  42. package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
  43. package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
  44. package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
  45. package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
  46. package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
  47. package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
  48. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-execute-continuation.json +1 -1
  49. package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
  50. package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
  51. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
  52. package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
  53. package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
  54. package/packages/omo-codex/plugin/package-lock.json +12 -12
  55. package/packages/omo-codex/plugin/package.json +1 -1
  56. package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
  57. package/packages/omo-codex/scripts/install-dist/install-local.mjs +2 -2
  58. package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
package/dist/index.js CHANGED
@@ -1383,7 +1383,7 @@ function applyEdits(text, edits) {
1383
1383
  }
1384
1384
  return text;
1385
1385
  }
1386
- var ScanError, SyntaxKind, parse2, ParseErrorCode;
1386
+ var ScanError, SyntaxKind, parse2, parseTree2, findNodeAtLocation2, ParseErrorCode;
1387
1387
  var init_main = __esm(() => {
1388
1388
  init_format();
1389
1389
  init_edit();
@@ -1418,6 +1418,8 @@ var init_main = __esm(() => {
1418
1418
  SyntaxKind[SyntaxKind["EOF"] = 17] = "EOF";
1419
1419
  })(SyntaxKind || (SyntaxKind = {}));
1420
1420
  parse2 = parse;
1421
+ parseTree2 = parseTree;
1422
+ findNodeAtLocation2 = findNodeAtLocation;
1421
1423
  (function(ParseErrorCode) {
1422
1424
  ParseErrorCode[ParseErrorCode["InvalidSymbol"] = 1] = "InvalidSymbol";
1423
1425
  ParseErrorCode[ParseErrorCode["InvalidNumberFormat"] = 2] = "InvalidNumberFormat";
@@ -21917,18 +21919,188 @@ function parseJsoncSafe2(content) {
21917
21919
  };
21918
21920
  }
21919
21921
 
21920
- // packages/omo-config-core/src/writer/writer.ts
21922
+ // packages/omo-config-core/src/writer/surgical-edit.ts
21921
21923
  init_main();
21922
- var EMPTY_OMO_CONFIG = `// OMO configuration
21923
- {
21924
- }
21925
- `;
21926
21924
  var FORMATTING_OPTIONS = {
21927
21925
  eol: `
21928
21926
  `,
21929
21927
  insertSpaces: true,
21930
21928
  tabSize: 2
21931
21929
  };
21930
+ function applyOmoConfigEdit(content, edit) {
21931
+ const fallback = formattedModify(content, edit);
21932
+ const surgical = surgicalEditPreservingEol(content, edit);
21933
+ if (surgical === undefined)
21934
+ return fallback;
21935
+ if (parses(fallback))
21936
+ return sameData(surgical, fallback) ? surgical : fallback;
21937
+ return parses(surgical) ? surgical : fallback;
21938
+ }
21939
+ function surgicalEditPreservingEol(content, edit) {
21940
+ const crlf = content.includes(`\r
21941
+ `);
21942
+ if (crlf && /(?<!\r)\n/.test(content))
21943
+ return;
21944
+ const text = crlf ? content.replaceAll(`\r
21945
+ `, `
21946
+ `) : content;
21947
+ const edited = surgicalEdit(text, edit);
21948
+ if (edited === undefined)
21949
+ return;
21950
+ return crlf ? edited.replaceAll(`
21951
+ `, `\r
21952
+ `) : edited;
21953
+ }
21954
+ function parses(content) {
21955
+ return parseJsoncSafe2(content).errors.length === 0;
21956
+ }
21957
+ function surgicalEdit(content, edit) {
21958
+ const root = parseTree2(content);
21959
+ if (root === undefined)
21960
+ return;
21961
+ const target = findNodeAtLocation2(root, [...edit.path]);
21962
+ if (target !== undefined)
21963
+ return edit.value === undefined ? removeMember(content, target) : undefined;
21964
+ if (edit.value === undefined)
21965
+ return content;
21966
+ return insertMember(content, root, edit);
21967
+ }
21968
+ function sameData(surgical, fallback) {
21969
+ const left = parseJsoncSafe2(surgical);
21970
+ const right = parseJsoncSafe2(fallback);
21971
+ if (left.errors.length > 0 || right.errors.length > 0)
21972
+ return false;
21973
+ return JSON.stringify(left.data) === JSON.stringify(right.data);
21974
+ }
21975
+ function formattedModify(content, edit) {
21976
+ return applyEdits(content, modify(content, [...edit.path], edit.value, { formattingOptions: FORMATTING_OPTIONS }));
21977
+ }
21978
+ function lineStart(content, offset) {
21979
+ return content.lastIndexOf(`
21980
+ `, offset - 1) + 1;
21981
+ }
21982
+ function lineEnd(content, offset) {
21983
+ const end = content.indexOf(`
21984
+ `, offset);
21985
+ return end === -1 ? content.length : end;
21986
+ }
21987
+ function leadingWhitespace(content, offset) {
21988
+ const start = lineStart(content, offset);
21989
+ return /^[ \t]*/.exec(content.slice(start))?.[0] ?? "";
21990
+ }
21991
+ function onlyWhitespaceBefore(content, offset) {
21992
+ return /^[ \t]*$/.test(content.slice(lineStart(content, offset), offset));
21993
+ }
21994
+ function commaAfter(content, offset) {
21995
+ const match = /^[ \t]*,/.exec(content.slice(offset));
21996
+ return match === null ? undefined : offset + match[0].length - 1;
21997
+ }
21998
+ function lineRestIsTrivia(content, offset) {
21999
+ const rest = content.slice(offset, lineEnd(content, offset));
22000
+ return /^[ \t]*,?[ \t]*(?:\/\/.*|\/\*(?:(?!\*\/).)*\*\/[ \t]*)?$/.test(rest);
22001
+ }
22002
+ function memberNodes(objectNode) {
22003
+ return (objectNode.children ?? []).filter((child) => child.type === "property");
22004
+ }
22005
+ function fileIndentUnit(content) {
22006
+ const indents = [...content.matchAll(/\n([ \t]+)\S/g)].map((match) => match[1] ?? "");
22007
+ if (indents.some((indent) => indent.startsWith("\t")))
22008
+ return "\t";
22009
+ const widths = indents.map((indent) => indent.length).filter((width) => width > 0);
22010
+ return " ".repeat(widths.length === 0 ? 2 : Math.min(...widths));
22011
+ }
22012
+ function indentUnit(content, memberIndent, objectIndent) {
22013
+ if (memberIndent.startsWith(objectIndent) && memberIndent.length > objectIndent.length) {
22014
+ return memberIndent.slice(objectIndent.length);
22015
+ }
22016
+ return fileIndentUnit(content);
22017
+ }
22018
+ function renderMember(key, value, memberIndent, unit) {
22019
+ const rendered = JSON.stringify(value, null, unit).split(`
22020
+ `).join(`
22021
+ ${memberIndent}`);
22022
+ return `${JSON.stringify(key)}: ${rendered}`;
22023
+ }
22024
+ function nestedValue(path, value) {
22025
+ return path.reduceRight((inner, segment) => ({ [String(segment)]: inner }), value);
22026
+ }
22027
+ function insertMember(content, root, edit) {
22028
+ let depth = edit.path.length - 1;
22029
+ let parent;
22030
+ while (depth >= 0) {
22031
+ parent = depth === 0 ? root : findNodeAtLocation2(root, [...edit.path.slice(0, depth)]);
22032
+ if (parent !== undefined)
22033
+ break;
22034
+ depth -= 1;
22035
+ }
22036
+ if (parent === undefined || parent.type !== "object")
22037
+ return;
22038
+ const key = edit.path[depth];
22039
+ if (typeof key !== "string")
22040
+ return;
22041
+ const value = nestedValue(edit.path.slice(depth + 1), edit.value);
22042
+ const objectIndent = leadingWhitespace(content, parent.offset);
22043
+ const closeBrace = parent.offset + parent.length - 1;
22044
+ const members = memberNodes(parent);
22045
+ const last = members.at(-1);
22046
+ if (last === undefined) {
22047
+ if (!/^\{\s*\}$/.test(content.slice(parent.offset, closeBrace + 1)))
22048
+ return;
22049
+ const unit = fileIndentUnit(content);
22050
+ const memberIndent = `${objectIndent}${unit}`;
22051
+ const member = renderMember(key, value, memberIndent, unit);
22052
+ return `${content.slice(0, parent.offset)}{
22053
+ ${memberIndent}${member}
22054
+ ${objectIndent}}${content.slice(closeBrace + 1)}`;
22055
+ }
22056
+ if (!onlyWhitespaceBefore(content, last.offset))
22057
+ return;
22058
+ const lastEnd = last.offset + last.length;
22059
+ if (!lineRestIsTrivia(content, lastEnd))
22060
+ return;
22061
+ const insertAt = lineEnd(content, lastEnd);
22062
+ if (insertAt >= closeBrace)
22063
+ return;
22064
+ const memberIndent = leadingWhitespace(content, last.offset);
22065
+ const unit = indentUnit(content, memberIndent, objectIndent);
22066
+ const trailingComma = commaAfter(content, lastEnd);
22067
+ const member = renderMember(key, value, memberIndent, unit);
22068
+ const head = trailingComma === undefined ? `${content.slice(0, lastEnd)},${content.slice(lastEnd, insertAt)}` : content.slice(0, insertAt);
22069
+ return `${head}
22070
+ ${memberIndent}${member}${trailingComma === undefined ? "" : ","}${content.slice(insertAt)}`;
22071
+ }
22072
+ function removeMember(content, valueNode) {
22073
+ const property = valueNode.parent;
22074
+ if (property?.type !== "property" || property.parent?.type !== "object")
22075
+ return;
22076
+ if (!onlyWhitespaceBefore(content, property.offset))
22077
+ return;
22078
+ const end = property.offset + property.length;
22079
+ if (!lineRestIsTrivia(content, end))
22080
+ return;
22081
+ const members = memberNodes(property.parent);
22082
+ const index = members.indexOf(property);
22083
+ const isLast = index === members.length - 1;
22084
+ const removeFrom = lineStart(content, property.offset);
22085
+ const lineAfter = lineEnd(content, end);
22086
+ const removeTo = lineAfter < content.length ? lineAfter + 1 : lineAfter;
22087
+ const removed = `${content.slice(0, removeFrom)}${content.slice(removeTo)}`;
22088
+ if (!isLast || commaAfter(content, end) !== undefined || index === 0)
22089
+ return removed;
22090
+ const previous = members[index - 1];
22091
+ if (previous === undefined)
22092
+ return removed;
22093
+ const previousComma = commaAfter(content, previous.offset + previous.length);
22094
+ if (previousComma === undefined)
22095
+ return removed;
22096
+ return `${removed.slice(0, previousComma)}${removed.slice(previousComma + 1)}`;
22097
+ }
22098
+
22099
+ // packages/omo-config-core/src/writer/writer.ts
22100
+ var EMPTY_OMO_CONFIG = `// OMO configuration
22101
+ {
22102
+ }
22103
+ `;
21932
22104
  function backupSuffix() {
21933
22105
  return new Date().toISOString().replace(/[:.]/g, "-");
21934
22106
  }
@@ -22053,7 +22225,7 @@ function updateOmoConfig(options) {
22053
22225
  }
22054
22226
  let nextContent = content;
22055
22227
  for (const edit of options.edits) {
22056
- nextContent = applyEdits(nextContent, modify(nextContent, [...edit.path], edit.value, { formattingOptions: FORMATTING_OPTIONS }));
22228
+ nextContent = applyOmoConfigEdit(nextContent, edit);
22057
22229
  }
22058
22230
  writeAtomically(path, nextContent, fileSystem);
22059
22231
  return backupPath === undefined ? { path } : { backupPath, path };
@@ -22089,6 +22261,54 @@ function moveMigrationBackup(fileSystem, sourcePath, backupPath) {
22089
22261
  // packages/omo-config-core/src/migration/commit.ts
22090
22262
  import { basename, dirname as dirname3, join as join3, resolve as resolve2 } from "path";
22091
22263
 
22264
+ // packages/omo-config-core/src/migration/diff-edits.ts
22265
+ function deepEqual(left, right) {
22266
+ if (left === right)
22267
+ return true;
22268
+ if (Array.isArray(left) || Array.isArray(right)) {
22269
+ if (!Array.isArray(left) || !Array.isArray(right) || left.length !== right.length)
22270
+ return false;
22271
+ return left.every((entry, index) => deepEqual(entry, right[index]));
22272
+ }
22273
+ if (!isPlainObject2(left) || !isPlainObject2(right))
22274
+ return false;
22275
+ const leftKeys = Object.keys(left);
22276
+ if (leftKeys.length !== Object.keys(right).length)
22277
+ return false;
22278
+ return leftKeys.every((key) => Object.prototype.hasOwnProperty.call(right, key) && deepEqual(left[key], right[key]));
22279
+ }
22280
+ function withoutMarker(document) {
22281
+ const { _migrations: _marker, ...rest } = document;
22282
+ return rest;
22283
+ }
22284
+ function diffEdits(before, after, path = []) {
22285
+ const edits = [];
22286
+ for (const key of Object.keys(before)) {
22287
+ if (isUnsafeObjectKey2(key))
22288
+ continue;
22289
+ if (!Object.prototype.hasOwnProperty.call(after, key))
22290
+ edits.push({ path: [...path, key], value: undefined });
22291
+ }
22292
+ for (const [key, value] of Object.entries(after)) {
22293
+ if (isUnsafeObjectKey2(key))
22294
+ continue;
22295
+ const nextPath = [...path, key];
22296
+ if (!Object.prototype.hasOwnProperty.call(before, key)) {
22297
+ edits.push({ path: nextPath, value });
22298
+ continue;
22299
+ }
22300
+ const previous = before[key];
22301
+ if (deepEqual(previous, value))
22302
+ continue;
22303
+ if (isPlainObject2(previous) && isPlainObject2(value)) {
22304
+ edits.push(...diffEdits(previous, value, nextPath));
22305
+ continue;
22306
+ }
22307
+ edits.push({ path: nextPath, value });
22308
+ }
22309
+ return edits;
22310
+ }
22311
+
22092
22312
  // packages/omo-config-core/src/migration/merge.ts
22093
22313
  function displayValue(value) {
22094
22314
  const encoded = JSON.stringify(value);
@@ -22346,17 +22566,11 @@ function prepareTargetReplacement(input) {
22346
22566
  const marker = markerValue(input.target, input.migrationId, input.targetPath);
22347
22567
  const document = { ...documentCleanup.document, _migrations: marker };
22348
22568
  validateTarget(input.targetPath, document);
22349
- const edits = [...targetCleanup.edits];
22350
- for (const key of Object.keys(targetCleanup.document)) {
22351
- if (key !== "_migrations" && !Object.prototype.hasOwnProperty.call(documentCleanup.document, key)) {
22352
- edits.push({ path: [key], value: undefined });
22353
- }
22354
- }
22355
- for (const [key, value] of Object.entries(documentCleanup.document)) {
22356
- if (key !== "_migrations")
22357
- edits.push({ path: [key], value });
22358
- }
22359
- edits.push({ path: ["_migrations"], value: marker });
22569
+ const edits = [
22570
+ ...targetCleanup.edits,
22571
+ ...diffEdits(withoutMarker(targetCleanup.document), withoutMarker(documentCleanup.document)),
22572
+ { path: ["_migrations"], value: marker }
22573
+ ];
22360
22574
  return {
22361
22575
  diagnostics: uniqueDiagnostics([...targetCleanup.diagnostics, ...documentCleanup.diagnostics]),
22362
22576
  document,
@@ -22890,20 +23104,20 @@ var AGENT_MODEL_REQUIREMENTS = {
22890
23104
  fallbackChain: [
22891
23105
  { providers: ["kimi-for-coding"], model: "kimi-for-coding-highspeed", variant: "off" },
22892
23106
  { providers: ["openai", "chatgpt-subscription"], model: "gpt-6-luna-fast", variant: "low" },
23107
+ { providers: ["anthropic", "github-copilot"], model: "claude-haiku-5-5", variant: "medium" },
22893
23108
  { providers: ["deepseek"], model: "deepseek-flash", variant: "max" },
22894
23109
  { providers: ["opencode-go", "bailian-coding-plan"], model: "qwen3.7-plus" },
22895
- { providers: ["opencode-go"], model: "minimax-m2.7" },
22896
- { providers: ["anthropic", "github-copilot"], model: "claude-haiku-4-5" }
23110
+ { providers: ["opencode-go"], model: "minimax-m2.7" }
22897
23111
  ]
22898
23112
  },
22899
23113
  explore: {
22900
23114
  fallbackChain: [
22901
23115
  { providers: ["kimi-for-coding"], model: "kimi-for-coding-highspeed", variant: "off" },
22902
23116
  { providers: ["openai", "chatgpt-subscription"], model: "gpt-6-luna-fast", variant: "low" },
23117
+ { providers: ["anthropic", "github-copilot"], model: "claude-haiku-5-5", variant: "medium" },
22903
23118
  { providers: ["deepseek"], model: "deepseek-flash", variant: "max" },
22904
23119
  { providers: ["opencode-go", "bailian-coding-plan"], model: "qwen3.7-plus" },
22905
- { providers: ["opencode-go"], model: "minimax-m2.7" },
22906
- { providers: ["anthropic", "github-copilot"], model: "claude-haiku-4-5" }
23120
+ { providers: ["opencode-go"], model: "minimax-m2.7" }
22907
23121
  ]
22908
23122
  },
22909
23123
  "multimodal-looker": {
@@ -23074,6 +23288,11 @@ var CATEGORY_MODEL_REQUIREMENTS = {
23074
23288
  quick: {
23075
23289
  fallbackChain: [
23076
23290
  { providers: ["openai", "chatgpt-subscription"], model: "gpt-6-luna-fast", variant: "low" },
23291
+ {
23292
+ providers: ["anthropic", "anthropic-api", "github-copilot"],
23293
+ model: "claude-haiku-5-5",
23294
+ variant: "medium"
23295
+ },
23077
23296
  { providers: ["deepseek"], model: "deepseek-flash", variant: "off" },
23078
23297
  {
23079
23298
  providers: ["qwen-token-plan", "alibaba-token-plan", "bailian-coding-plan"],
@@ -23083,11 +23302,6 @@ var CATEGORY_MODEL_REQUIREMENTS = {
23083
23302
  { providers: ["opencode-go"], model: "minimax-m3", variant: "max" },
23084
23303
  { providers: ["opencode-go"], model: "minimax-m2.7", variant: "max" },
23085
23304
  { providers: ["xai"], model: "grok-4.20-0309-non-reasoning" },
23086
- {
23087
- providers: ["anthropic", "anthropic-api", "github-copilot"],
23088
- model: "claude-haiku-4-5",
23089
- variant: "off"
23090
- },
23091
23305
  { providers: ["zai-coding-plan"], model: "glm-5.3-flash", variant: "low" },
23092
23306
  { providers: ["xiaomi"], model: "mimo-v2.6-flash", variant: "low" }
23093
23307
  ]
@@ -29025,21 +29239,27 @@ function ensureExecutable(binaryPath) {
29025
29239
  chmodSync(binaryPath, 493);
29026
29240
  }
29027
29241
  }
29242
+ var BSDTAR_LISTING_LINE = /^([^\s])\S*\s+\d+\s+\S+\s+\S+\s+\d+\s+(?:\d+\s+\S+(?:\s+\S+)??|\S+(?:\s+\S+)??\s+\d+)\s+(?:\d{2}:\d{2}|\d{4})\s+(.*)$/;
29243
+ var GNU_TAR_LISTING_LINE = /^([^\s])\S*\s+\S+\/\S+\s+\d+\s+\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}(?::\d{2})?\s+(.*)$/;
29028
29244
  function parseTarEntry(line) {
29029
- const match = line.match(/^([^\s])\S*\s+\d+\s+\S+\s+\S+\s+\d+\s+\w+\s+\d+\s+(?:\d{2}:\d{2}|\d{4})\s+(.*)$/);
29245
+ const match = line.match(BSDTAR_LISTING_LINE) ?? line.match(GNU_TAR_LISTING_LINE);
29030
29246
  if (!match) {
29031
29247
  return null;
29032
29248
  }
29033
29249
  const [, rawType, rawEntryPath] = match;
29034
29250
  if (rawType === "l" || rawType === "h") {
29035
- const arrowIndex = rawEntryPath.lastIndexOf(" -> ");
29036
- if (arrowIndex === -1) {
29251
+ const separator = rawType === "h" && rawEntryPath.includes(" link to ") ? " link to " : " -> ";
29252
+ const separatorIndex = rawEntryPath.lastIndexOf(separator);
29253
+ if (separatorIndex === -1) {
29037
29254
  return { path: rawEntryPath, type: rawType === "l" ? "symlink" : "hardlink" };
29038
29255
  }
29256
+ if (rawEntryPath.indexOf(separator) !== separatorIndex) {
29257
+ return null;
29258
+ }
29039
29259
  return {
29040
- path: rawEntryPath.slice(0, arrowIndex),
29260
+ path: rawEntryPath.slice(0, separatorIndex),
29041
29261
  type: rawType === "l" ? "symlink" : "hardlink",
29042
- linkPath: rawEntryPath.slice(arrowIndex + 4)
29262
+ linkPath: rawEntryPath.slice(separatorIndex + separator.length)
29043
29263
  };
29044
29264
  }
29045
29265
  return {
@@ -29048,8 +29268,11 @@ function parseTarEntry(line) {
29048
29268
  };
29049
29269
  }
29050
29270
  async function listTarEntries(archivePath, cwd) {
29051
- const proc = spawn(["tar", "-tvzf", archivePath], {
29271
+ const env = { ...process.env, LC_ALL: "C" };
29272
+ delete env.TAR_OPTIONS;
29273
+ const proc = spawn(["tar", "--numeric-owner", "-tvzf", archivePath], {
29052
29274
  cwd,
29275
+ env,
29053
29276
  stdout: "pipe",
29054
29277
  stderr: "pipe"
29055
29278
  });
@@ -29064,7 +29287,21 @@ async function listTarEntries(archivePath, cwd) {
29064
29287
  if (exitCode !== 0) {
29065
29288
  throw new Error(`tar entry listing failed (exit ${exitCode}): ${stderr}`);
29066
29289
  }
29067
- return stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean).map((line) => parseTarEntry(line)).filter((entry) => entry !== null);
29290
+ const listingLines = stdout.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
29291
+ const entries = [];
29292
+ let unparsedLineCount = 0;
29293
+ for (const listingLine of listingLines) {
29294
+ const entry = parseTarEntry(listingLine);
29295
+ if (entry === null) {
29296
+ unparsedLineCount += 1;
29297
+ } else {
29298
+ entries.push(entry);
29299
+ }
29300
+ }
29301
+ if (unparsedLineCount > 0) {
29302
+ throw new Error(`tar entry listing failed: ${unparsedLineCount}/${listingLines.length} tar listing lines could not be parsed (fail-closed)`);
29303
+ }
29304
+ return entries;
29068
29305
  }
29069
29306
  // packages/omo-opencode/src/shared/write-file-atomically.ts
29070
29307
  import {
@@ -83689,6 +83926,237 @@ var model_capabilities_generated_default = {
83689
83926
  input: 1048576,
83690
83927
  output: 131072
83691
83928
  }
83929
+ },
83930
+ "claude-haiku-5-5": {
83931
+ id: "claude-haiku-5-5",
83932
+ family: "claude-haiku",
83933
+ reasoning: true,
83934
+ temperature: false,
83935
+ toolCall: true,
83936
+ modalities: {
83937
+ input: [
83938
+ "text",
83939
+ "image",
83940
+ "pdf"
83941
+ ],
83942
+ output: [
83943
+ "text"
83944
+ ]
83945
+ },
83946
+ limit: {
83947
+ context: 1e6,
83948
+ output: 128000
83949
+ }
83950
+ },
83951
+ "claude-haiku-5-5@default": {
83952
+ id: "claude-haiku-5-5@default",
83953
+ family: "claude-haiku",
83954
+ reasoning: true,
83955
+ temperature: false,
83956
+ toolCall: true,
83957
+ modalities: {
83958
+ input: [
83959
+ "text",
83960
+ "image",
83961
+ "pdf"
83962
+ ],
83963
+ output: [
83964
+ "text"
83965
+ ]
83966
+ },
83967
+ limit: {
83968
+ context: 1e6,
83969
+ output: 128000
83970
+ }
83971
+ },
83972
+ "au.anthropic.claude-haiku-5-5": {
83973
+ id: "au.anthropic.claude-haiku-5-5",
83974
+ family: "claude-haiku",
83975
+ reasoning: true,
83976
+ temperature: false,
83977
+ toolCall: true,
83978
+ modalities: {
83979
+ input: [
83980
+ "text",
83981
+ "image",
83982
+ "pdf"
83983
+ ],
83984
+ output: [
83985
+ "text"
83986
+ ]
83987
+ },
83988
+ limit: {
83989
+ context: 1e6,
83990
+ output: 128000
83991
+ }
83992
+ },
83993
+ "anthropic.claude-haiku-5-5": {
83994
+ id: "anthropic.claude-haiku-5-5",
83995
+ family: "claude-haiku",
83996
+ reasoning: true,
83997
+ temperature: false,
83998
+ toolCall: true,
83999
+ modalities: {
84000
+ input: [
84001
+ "text",
84002
+ "image",
84003
+ "pdf"
84004
+ ],
84005
+ output: [
84006
+ "text"
84007
+ ]
84008
+ },
84009
+ limit: {
84010
+ context: 1e6,
84011
+ output: 128000
84012
+ }
84013
+ },
84014
+ "eu.anthropic.claude-haiku-5-5": {
84015
+ id: "eu.anthropic.claude-haiku-5-5",
84016
+ family: "claude-haiku",
84017
+ reasoning: true,
84018
+ temperature: false,
84019
+ toolCall: true,
84020
+ modalities: {
84021
+ input: [
84022
+ "text",
84023
+ "image",
84024
+ "pdf"
84025
+ ],
84026
+ output: [
84027
+ "text"
84028
+ ]
84029
+ },
84030
+ limit: {
84031
+ context: 1e6,
84032
+ output: 128000
84033
+ }
84034
+ },
84035
+ "global.anthropic.claude-haiku-5-5": {
84036
+ id: "global.anthropic.claude-haiku-5-5",
84037
+ family: "claude-haiku",
84038
+ reasoning: true,
84039
+ temperature: false,
84040
+ toolCall: true,
84041
+ modalities: {
84042
+ input: [
84043
+ "text",
84044
+ "image",
84045
+ "pdf"
84046
+ ],
84047
+ output: [
84048
+ "text"
84049
+ ]
84050
+ },
84051
+ limit: {
84052
+ context: 1e6,
84053
+ output: 128000
84054
+ }
84055
+ },
84056
+ "jp.anthropic.claude-haiku-5-5": {
84057
+ id: "jp.anthropic.claude-haiku-5-5",
84058
+ family: "claude-haiku",
84059
+ reasoning: true,
84060
+ temperature: false,
84061
+ toolCall: true,
84062
+ modalities: {
84063
+ input: [
84064
+ "text",
84065
+ "image",
84066
+ "pdf"
84067
+ ],
84068
+ output: [
84069
+ "text"
84070
+ ]
84071
+ },
84072
+ limit: {
84073
+ context: 1e6,
84074
+ output: 128000
84075
+ }
84076
+ },
84077
+ "us.anthropic.claude-haiku-5-5": {
84078
+ id: "us.anthropic.claude-haiku-5-5",
84079
+ family: "claude-haiku",
84080
+ reasoning: true,
84081
+ temperature: false,
84082
+ toolCall: true,
84083
+ modalities: {
84084
+ input: [
84085
+ "text",
84086
+ "image",
84087
+ "pdf"
84088
+ ],
84089
+ output: [
84090
+ "text"
84091
+ ]
84092
+ },
84093
+ limit: {
84094
+ context: 1e6,
84095
+ output: 128000
84096
+ }
84097
+ },
84098
+ "anthropic/claude-haiku-5-5": {
84099
+ id: "anthropic/claude-haiku-5-5",
84100
+ family: "claude-haiku",
84101
+ reasoning: true,
84102
+ temperature: false,
84103
+ toolCall: true,
84104
+ modalities: {
84105
+ input: [
84106
+ "text",
84107
+ "image"
84108
+ ],
84109
+ output: [
84110
+ "text"
84111
+ ]
84112
+ },
84113
+ limit: {
84114
+ context: 1e6,
84115
+ output: 128000
84116
+ }
84117
+ },
84118
+ "claude-haiku-5.5": {
84119
+ id: "claude-haiku-5.5",
84120
+ family: "claude-haiku",
84121
+ reasoning: true,
84122
+ temperature: false,
84123
+ toolCall: true,
84124
+ modalities: {
84125
+ input: [
84126
+ "text",
84127
+ "image",
84128
+ "pdf"
84129
+ ],
84130
+ output: [
84131
+ "text"
84132
+ ]
84133
+ },
84134
+ limit: {
84135
+ context: 1e6,
84136
+ output: 128000
84137
+ }
84138
+ },
84139
+ "anthropic/claude-haiku-5.5": {
84140
+ id: "anthropic/claude-haiku-5.5",
84141
+ family: "claude-haiku",
84142
+ reasoning: true,
84143
+ temperature: false,
84144
+ toolCall: true,
84145
+ modalities: {
84146
+ input: [
84147
+ "text",
84148
+ "image",
84149
+ "pdf"
84150
+ ],
84151
+ output: [
84152
+ "text"
84153
+ ]
84154
+ },
84155
+ limit: {
84156
+ context: 1e6,
84157
+ input: 1e6,
84158
+ output: 128000
84159
+ }
83692
84160
  }
83693
84161
  }
83694
84162
  };
@@ -87732,7 +88200,7 @@ var ANTHROPIC_PREFIX = "anthropic/";
87732
88200
  var CLAUDE_CODE_ALIAS_MAP = new Map([
87733
88201
  ["sonnet", `${ANTHROPIC_PREFIX}claude-sonnet-4-6`],
87734
88202
  ["opus", `${ANTHROPIC_PREFIX}claude-opus-4-8`],
87735
- ["haiku", `${ANTHROPIC_PREFIX}claude-haiku-4-5`]
88203
+ ["haiku", `${ANTHROPIC_PREFIX}claude-haiku-5-5`]
87736
88204
  ]);
87737
88205
  function mapClaudeModelString(model, anthropicProvider) {
87738
88206
  if (!model)
@@ -98674,7 +99142,7 @@ function getCachedVersion(options = {}) {
98674
99142
  // package.json
98675
99143
  var package_default = {
98676
99144
  name: "oh-my-opencode",
98677
- version: "5.1.26",
99145
+ version: "5.1.28",
98678
99146
  description: "The Best AI Agent Harness - Batteries-Included OpenCode Plugin with Multi-Model Orchestration, Parallel Background Agents, and Crafted LSP/AST Tools",
98679
99147
  main: "./dist/index.js",
98680
99148
  types: "dist/index.d.ts",
@@ -98851,7 +99319,7 @@ var package_default = {
98851
99319
  },
98852
99320
  devDependencies: {
98853
99321
  "@clack/prompts": "^1.8.1",
98854
- "@code-yeongyu/senpi": "2026.10.10-8",
99322
+ "@code-yeongyu/senpi": "2026.10.10-10",
98855
99323
  "@modelcontextprotocol/sdk": "^1.30.0",
98856
99324
  "@oh-my-opencode/agents-md-core": "workspace:*",
98857
99325
  "@oh-my-opencode/ast-grep-mcp": "workspace:*",
@@ -98909,18 +99377,18 @@ var package_default = {
98909
99377
  typescript: "^7.0.2"
98910
99378
  },
98911
99379
  optionalDependencies: {
98912
- "oh-my-opencode-darwin-arm64": "5.1.26",
98913
- "oh-my-opencode-darwin-x64": "5.1.26",
98914
- "oh-my-opencode-darwin-x64-baseline": "5.1.26",
98915
- "oh-my-opencode-linux-arm64": "5.1.26",
98916
- "oh-my-opencode-linux-arm64-musl": "5.1.26",
98917
- "oh-my-opencode-linux-x64": "5.1.26",
98918
- "oh-my-opencode-linux-x64-baseline": "5.1.26",
98919
- "oh-my-opencode-linux-x64-musl": "5.1.26",
98920
- "oh-my-opencode-linux-x64-musl-baseline": "5.1.26",
98921
- "oh-my-opencode-windows-arm64": "5.1.26",
98922
- "oh-my-opencode-windows-x64": "5.1.26",
98923
- "oh-my-opencode-windows-x64-baseline": "5.1.26"
99380
+ "oh-my-opencode-darwin-arm64": "5.1.28",
99381
+ "oh-my-opencode-darwin-x64": "5.1.28",
99382
+ "oh-my-opencode-darwin-x64-baseline": "5.1.28",
99383
+ "oh-my-opencode-linux-arm64": "5.1.28",
99384
+ "oh-my-opencode-linux-arm64-musl": "5.1.28",
99385
+ "oh-my-opencode-linux-x64": "5.1.28",
99386
+ "oh-my-opencode-linux-x64-baseline": "5.1.28",
99387
+ "oh-my-opencode-linux-x64-musl": "5.1.28",
99388
+ "oh-my-opencode-linux-x64-musl-baseline": "5.1.28",
99389
+ "oh-my-opencode-windows-arm64": "5.1.28",
99390
+ "oh-my-opencode-windows-x64": "5.1.28",
99391
+ "oh-my-opencode-windows-x64-baseline": "5.1.28"
98924
99392
  },
98925
99393
  overrides: {
98926
99394
  hono: "^4.13.8",
@@ -121932,7 +122400,7 @@ function equalsIgnoringWhitespace(a, b) {
121932
122400
  return true;
121933
122401
  return a.replace(/\s+/g, "") === b.replace(/\s+/g, "");
121934
122402
  }
121935
- function leadingWhitespace(text) {
122403
+ function leadingWhitespace2(text) {
121936
122404
  if (!text)
121937
122405
  return "";
121938
122406
  const match = text.match(/^\s*/);
@@ -121977,10 +122445,10 @@ function toNewLines(input) {
121977
122445
  function restoreLeadingIndent(templateLine, line) {
121978
122446
  if (line.length === 0)
121979
122447
  return line;
121980
- const templateIndent = leadingWhitespace(templateLine);
122448
+ const templateIndent = leadingWhitespace2(templateLine);
121981
122449
  if (templateIndent.length === 0)
121982
122450
  return line;
121983
- if (leadingWhitespace(line).length > 0)
122451
+ if (leadingWhitespace2(line).length > 0)
121984
122452
  return line;
121985
122453
  if (templateLine.trim() === line.trim())
121986
122454
  return line;
@@ -122119,7 +122587,7 @@ function stripTrailingContinuationTokens(text) {
122119
122587
  function stripMergeOperatorChars(text) {
122120
122588
  return text.replace(/[|&?]/g, "");
122121
122589
  }
122122
- function leadingWhitespace2(text) {
122590
+ function leadingWhitespace3(text) {
122123
122591
  if (!text)
122124
122592
  return "";
122125
122593
  const match = text.match(/^\s*/);
@@ -122247,9 +122715,9 @@ function restoreIndentForPairedReplacement(originalLines, replacementLines) {
122247
122715
  return replacementLines.map((line, idx) => {
122248
122716
  if (line.length === 0)
122249
122717
  return line;
122250
- if (leadingWhitespace2(line).length > 0)
122718
+ if (leadingWhitespace3(line).length > 0)
122251
122719
  return line;
122252
- const indent = leadingWhitespace2(originalLines[idx]);
122720
+ const indent = leadingWhitespace3(originalLines[idx]);
122253
122721
  if (indent.length === 0)
122254
122722
  return line;
122255
122723
  if (originalLines[idx].trim() === line.trim())
@@ -159286,7 +159754,7 @@ At a handoff - turn start (after the intent line), a todo phase change, a blocke
159286
159754
 
159287
159755
  [Outcome so far] toward [the user's original ask and the result they wanted]. You need: [ledger N/M done, findings, blockers]. Now: [todo task in progress]. Next: [next open task].
159288
159756
 
159289
- Now and Next are todo labels verbatim; the Next stated is executed in this same response with tool calls. Between handoffs, no narration. Final answers state what changed, where, the verification evidence, and any real residual risk - dense and short.
159757
+ Now and Next are todo labels verbatim; the Next stated is executed in this same response with tool calls. Between handoffs, no narration. The block is for multi-step work tracked in todos. A request finished in a single turn with no todo list gets a plain answer with no block, and a final message never opens or closes with ledger lines such as \`Next: none\`. Final answers state what changed, where, the verification evidence, and any real residual risk - dense and short.
159290
159758
  </communication>`;
159291
159759
  const constraintsBlock = `<constraints>
159292
159760
  ${hardBlocks}
@@ -163020,7 +163488,7 @@ AGENTS.md files carry directory-scoped conventions. Obey them for files in their
163020
163488
 
163021
163489
  [Outcome so far] toward [the user's original ask and the result they wanted]. You need: [ledger N/M done, findings, blockers]. Now: [todo task in progress]. Next: [next open task].
163022
163490
 
163023
- Now and Next are todo labels verbatim; the Next stated is executed in this same response with tool calls. Between handoffs, no narration.
163491
+ Now and Next are todo labels verbatim; the Next stated is executed in this same response with tool calls. Between handoffs, no narration. The block is for multi-step work tracked in todos. A request finished in a single turn with no todo list gets a plain answer with no block, and a final message never opens or closes with ledger lines such as \`Next: none\`.
163024
163492
 
163025
163493
  **Final message.** Lead with the result. Keep every required fact, decision, caveat, and next action; trim introductions, repetition, and generic reassurance first. Group by user-facing outcome, not by file. Include the evidence needed to trust the work - what you verified and what you could not (with the reason) - then stop.
163026
163494