oh-my-opencode 3.1.4 → 3.1.5

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.
package/dist/index.js CHANGED
@@ -236,6 +236,9 @@ function createSystemDirective(type) {
236
236
  function isSystemDirective(text) {
237
237
  return text.trimStart().startsWith(SYSTEM_DIRECTIVE_PREFIX);
238
238
  }
239
+ function removeSystemReminders(text) {
240
+ return text.replace(/<system-reminder>[\s\S]*?<\/system-reminder>/gi, "").trim();
241
+ }
239
242
  var SYSTEM_DIRECTIVE_PREFIX = "[SYSTEM DIRECTIVE: OH-MY-OPENCODE", SystemDirectiveTypes;
240
243
  var init_system_directive = __esm(() => {
241
244
  SystemDirectiveTypes = {
@@ -4550,9 +4553,56 @@ var TAURI_APP_IDENTIFIER = "ai.opencode.desktop", TAURI_APP_IDENTIFIER_DEV = "ai
4550
4553
  var init_opencode_config_dir = () => {};
4551
4554
 
4552
4555
  // src/shared/opencode-version.ts
4553
- var NOT_CACHED;
4556
+ import { execSync } from "child_process";
4557
+ function parseVersion(version) {
4558
+ const cleaned = version.replace(/^v/, "").split("-")[0];
4559
+ return cleaned.split(".").map((n) => parseInt(n, 10) || 0);
4560
+ }
4561
+ function compareVersions(a, b) {
4562
+ const partsA = parseVersion(a);
4563
+ const partsB = parseVersion(b);
4564
+ const maxLen = Math.max(partsA.length, partsB.length);
4565
+ for (let i2 = 0;i2 < maxLen; i2++) {
4566
+ const numA = partsA[i2] ?? 0;
4567
+ const numB = partsB[i2] ?? 0;
4568
+ if (numA < numB)
4569
+ return -1;
4570
+ if (numA > numB)
4571
+ return 1;
4572
+ }
4573
+ return 0;
4574
+ }
4575
+ function isVersionGte(a, b) {
4576
+ return compareVersions(a, b) >= 0;
4577
+ }
4578
+ function getOpenCodeVersion() {
4579
+ if (cachedVersion !== NOT_CACHED) {
4580
+ return cachedVersion;
4581
+ }
4582
+ try {
4583
+ const result = execSync("opencode --version", {
4584
+ encoding: "utf-8",
4585
+ timeout: 5000,
4586
+ stdio: ["pipe", "pipe", "pipe"]
4587
+ }).trim();
4588
+ const versionMatch = result.match(/(\d+\.\d+\.\d+(?:-[\w.]+)?)/);
4589
+ cachedVersion = versionMatch?.[1] ?? null;
4590
+ return cachedVersion;
4591
+ } catch {
4592
+ cachedVersion = null;
4593
+ return null;
4594
+ }
4595
+ }
4596
+ function isOpenCodeVersionAtLeast(version) {
4597
+ const current = getOpenCodeVersion();
4598
+ if (!current)
4599
+ return true;
4600
+ return isVersionGte(current, version);
4601
+ }
4602
+ var OPENCODE_NATIVE_AGENTS_INJECTION_VERSION = "1.1.37", NOT_CACHED, cachedVersion;
4554
4603
  var init_opencode_version = __esm(() => {
4555
4604
  NOT_CACHED = Symbol("NOT_CACHED");
4605
+ cachedVersion = NOT_CACHED;
4556
4606
  });
4557
4607
 
4558
4608
  // src/shared/permission-compat.ts
@@ -4783,6 +4833,131 @@ function equalsIgnoreCase(a, b) {
4783
4833
  return a.toLowerCase() === b.toLowerCase();
4784
4834
  }
4785
4835
 
4836
+ // src/shared/model-requirements.ts
4837
+ var AGENT_MODEL_REQUIREMENTS, CATEGORY_MODEL_REQUIREMENTS;
4838
+ var init_model_requirements = __esm(() => {
4839
+ AGENT_MODEL_REQUIREMENTS = {
4840
+ sisyphus: {
4841
+ fallbackChain: [
4842
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4843
+ { providers: ["zai-coding-plan"], model: "glm-4.7" },
4844
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2-codex", variant: "medium" },
4845
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
4846
+ ]
4847
+ },
4848
+ oracle: {
4849
+ fallbackChain: [
4850
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
4851
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4852
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
4853
+ ]
4854
+ },
4855
+ librarian: {
4856
+ fallbackChain: [
4857
+ { providers: ["zai-coding-plan"], model: "glm-4.7" },
4858
+ { providers: ["opencode"], model: "big-pickle" },
4859
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" }
4860
+ ]
4861
+ },
4862
+ explore: {
4863
+ fallbackChain: [
4864
+ { providers: ["anthropic", "opencode"], model: "claude-haiku-4-5" },
4865
+ { providers: ["github-copilot"], model: "gpt-5-mini" },
4866
+ { providers: ["opencode"], model: "gpt-5-nano" }
4867
+ ]
4868
+ },
4869
+ "multimodal-looker": {
4870
+ fallbackChain: [
4871
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
4872
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" },
4873
+ { providers: ["zai-coding-plan"], model: "glm-4.6v" },
4874
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-haiku-4-5" },
4875
+ { providers: ["opencode"], model: "gpt-5-nano" }
4876
+ ]
4877
+ },
4878
+ prometheus: {
4879
+ fallbackChain: [
4880
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4881
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
4882
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
4883
+ ]
4884
+ },
4885
+ metis: {
4886
+ fallbackChain: [
4887
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4888
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
4889
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" }
4890
+ ]
4891
+ },
4892
+ momus: {
4893
+ fallbackChain: [
4894
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "medium" },
4895
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5" },
4896
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" }
4897
+ ]
4898
+ },
4899
+ atlas: {
4900
+ fallbackChain: [
4901
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" },
4902
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" },
4903
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
4904
+ ]
4905
+ }
4906
+ };
4907
+ CATEGORY_MODEL_REQUIREMENTS = {
4908
+ "visual-engineering": {
4909
+ fallbackChain: [
4910
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" },
4911
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4912
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" }
4913
+ ]
4914
+ },
4915
+ ultrabrain: {
4916
+ fallbackChain: [
4917
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2-codex", variant: "xhigh" },
4918
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4919
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
4920
+ ]
4921
+ },
4922
+ artistry: {
4923
+ fallbackChain: [
4924
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" },
4925
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4926
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" }
4927
+ ]
4928
+ },
4929
+ quick: {
4930
+ fallbackChain: [
4931
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-haiku-4-5" },
4932
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
4933
+ { providers: ["opencode"], model: "gpt-5-nano" }
4934
+ ]
4935
+ },
4936
+ "unspecified-low": {
4937
+ fallbackChain: [
4938
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" },
4939
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2-codex", variant: "medium" },
4940
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" }
4941
+ ]
4942
+ },
4943
+ "unspecified-high": {
4944
+ fallbackChain: [
4945
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4946
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
4947
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
4948
+ ]
4949
+ },
4950
+ writing: {
4951
+ fallbackChain: [
4952
+ { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
4953
+ { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" },
4954
+ { providers: ["zai-coding-plan"], model: "glm-4.7" },
4955
+ { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" }
4956
+ ]
4957
+ }
4958
+ };
4959
+ });
4960
+
4786
4961
  // src/shared/agent-variant.ts
4787
4962
  function resolveAgentVariant(config, agentName) {
4788
4963
  if (!agentName) {
@@ -4802,13 +4977,39 @@ function resolveAgentVariant(config, agentName) {
4802
4977
  }
4803
4978
  return config.categories?.[categoryName]?.variant;
4804
4979
  }
4980
+ function resolveVariantForModel(config, agentName, currentModel) {
4981
+ const agentRequirement = AGENT_MODEL_REQUIREMENTS[agentName];
4982
+ if (agentRequirement) {
4983
+ return findVariantInChain(agentRequirement.fallbackChain, currentModel.providerID);
4984
+ }
4985
+ const agentOverrides = config.agents;
4986
+ const agentOverride = agentOverrides ? findCaseInsensitive(agentOverrides, agentName) : undefined;
4987
+ const categoryName = agentOverride?.category;
4988
+ if (categoryName) {
4989
+ const categoryRequirement = CATEGORY_MODEL_REQUIREMENTS[categoryName];
4990
+ if (categoryRequirement) {
4991
+ return findVariantInChain(categoryRequirement.fallbackChain, currentModel.providerID);
4992
+ }
4993
+ }
4994
+ return;
4995
+ }
4996
+ function findVariantInChain(fallbackChain, providerID) {
4997
+ for (const entry of fallbackChain) {
4998
+ if (entry.providers.includes(providerID)) {
4999
+ return entry.variant;
5000
+ }
5001
+ }
5002
+ return;
5003
+ }
4805
5004
  function applyAgentVariant(config, agentName, message) {
4806
5005
  const variant = resolveAgentVariant(config, agentName);
4807
5006
  if (variant !== undefined && message.variant === undefined) {
4808
5007
  message.variant = variant;
4809
5008
  }
4810
5009
  }
4811
- var init_agent_variant = () => {};
5010
+ var init_agent_variant = __esm(() => {
5011
+ init_model_requirements();
5012
+ });
4812
5013
 
4813
5014
  // src/shared/session-cursor.ts
4814
5015
  function buildMessageKey(message, index) {
@@ -4942,131 +5143,6 @@ var init_agent_tool_restrictions = __esm(() => {
4942
5143
  };
4943
5144
  });
4944
5145
 
4945
- // src/shared/model-requirements.ts
4946
- var AGENT_MODEL_REQUIREMENTS, CATEGORY_MODEL_REQUIREMENTS;
4947
- var init_model_requirements = __esm(() => {
4948
- AGENT_MODEL_REQUIREMENTS = {
4949
- sisyphus: {
4950
- fallbackChain: [
4951
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4952
- { providers: ["zai-coding-plan"], model: "glm-4.7" },
4953
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2-codex", variant: "medium" },
4954
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
4955
- ]
4956
- },
4957
- oracle: {
4958
- fallbackChain: [
4959
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
4960
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4961
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
4962
- ]
4963
- },
4964
- librarian: {
4965
- fallbackChain: [
4966
- { providers: ["zai-coding-plan"], model: "glm-4.7" },
4967
- { providers: ["opencode"], model: "big-pickle" },
4968
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" }
4969
- ]
4970
- },
4971
- explore: {
4972
- fallbackChain: [
4973
- { providers: ["anthropic", "opencode"], model: "claude-haiku-4-5" },
4974
- { providers: ["github-copilot"], model: "gpt-5-mini" },
4975
- { providers: ["opencode"], model: "gpt-5-nano" }
4976
- ]
4977
- },
4978
- "multimodal-looker": {
4979
- fallbackChain: [
4980
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
4981
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" },
4982
- { providers: ["zai-coding-plan"], model: "glm-4.6v" },
4983
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-haiku-4-5" },
4984
- { providers: ["opencode"], model: "gpt-5-nano" }
4985
- ]
4986
- },
4987
- prometheus: {
4988
- fallbackChain: [
4989
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4990
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
4991
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
4992
- ]
4993
- },
4994
- metis: {
4995
- fallbackChain: [
4996
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
4997
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
4998
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" }
4999
- ]
5000
- },
5001
- momus: {
5002
- fallbackChain: [
5003
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "medium" },
5004
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5" },
5005
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" }
5006
- ]
5007
- },
5008
- atlas: {
5009
- fallbackChain: [
5010
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" },
5011
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" },
5012
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
5013
- ]
5014
- }
5015
- };
5016
- CATEGORY_MODEL_REQUIREMENTS = {
5017
- "visual-engineering": {
5018
- fallbackChain: [
5019
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" },
5020
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
5021
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" }
5022
- ]
5023
- },
5024
- ultrabrain: {
5025
- fallbackChain: [
5026
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2-codex", variant: "xhigh" },
5027
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
5028
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
5029
- ]
5030
- },
5031
- artistry: {
5032
- fallbackChain: [
5033
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro", variant: "max" },
5034
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
5035
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" }
5036
- ]
5037
- },
5038
- quick: {
5039
- fallbackChain: [
5040
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-haiku-4-5" },
5041
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
5042
- { providers: ["opencode"], model: "gpt-5-nano" }
5043
- ]
5044
- },
5045
- "unspecified-low": {
5046
- fallbackChain: [
5047
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" },
5048
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2-codex", variant: "medium" },
5049
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" }
5050
- ]
5051
- },
5052
- "unspecified-high": {
5053
- fallbackChain: [
5054
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-opus-4-5", variant: "max" },
5055
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2", variant: "high" },
5056
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-pro" }
5057
- ]
5058
- },
5059
- writing: {
5060
- fallbackChain: [
5061
- { providers: ["google", "github-copilot", "opencode"], model: "gemini-3-flash" },
5062
- { providers: ["anthropic", "github-copilot", "opencode"], model: "claude-sonnet-4-5" },
5063
- { providers: ["zai-coding-plan"], model: "glm-4.7" },
5064
- { providers: ["openai", "github-copilot", "opencode"], model: "gpt-5.2" }
5065
- ]
5066
- }
5067
- };
5068
- });
5069
-
5070
5146
  // src/shared/connected-providers-cache.ts
5071
5147
  import { existsSync as existsSync9, readFileSync as readFileSync6, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3 } from "fs";
5072
5148
  import { join as join12 } from "path";
@@ -7531,9 +7607,9 @@ v${latestVersion} available. Restart OpenCode to apply.` : `OpenCode is now on S
7531
7607
  return;
7532
7608
  hasChecked = true;
7533
7609
  setTimeout(async () => {
7534
- const cachedVersion = getCachedVersion();
7610
+ const cachedVersion2 = getCachedVersion();
7535
7611
  const localDevVersion = getLocalDevVersion(ctx.directory);
7536
- const displayVersion = localDevVersion ?? cachedVersion;
7612
+ const displayVersion = localDevVersion ?? cachedVersion2;
7537
7613
  await showConfigErrorsIfAny(ctx);
7538
7614
  await showModelCacheWarningIfNeeded(ctx);
7539
7615
  await updateAndShowConnectedProvidersCacheStatus(ctx);
@@ -7560,8 +7636,8 @@ async function runBackgroundUpdateCheck(ctx, autoUpdate, getToastMessage) {
7560
7636
  log("[auto-update-checker] Plugin not found in config");
7561
7637
  return;
7562
7638
  }
7563
- const cachedVersion = getCachedVersion();
7564
- const currentVersion = cachedVersion ?? pluginInfo.pinnedVersion;
7639
+ const cachedVersion2 = getCachedVersion();
7640
+ const currentVersion = cachedVersion2 ?? pluginInfo.pinnedVersion;
7565
7641
  if (!currentVersion) {
7566
7642
  log("[auto-update-checker] No version found (cached or pinned)");
7567
7643
  return;
@@ -18505,7 +18581,7 @@ async function executePreToolUseHooks(ctx, config, extendedConfig) {
18505
18581
  }
18506
18582
  if (result.stdout) {
18507
18583
  try {
18508
- const output = JSON.parse(result.stdout);
18584
+ const output = JSON.parse(result.stdout || "{}");
18509
18585
  let decision;
18510
18586
  let reason;
18511
18587
  let modifiedInput;
@@ -18741,7 +18817,7 @@ ${result.stderr.trim()}`);
18741
18817
  }
18742
18818
  if (result.exitCode === 0 && result.stdout) {
18743
18819
  try {
18744
- const output = JSON.parse(result.stdout);
18820
+ const output = JSON.parse(result.stdout || "{}");
18745
18821
  if (output.decision === "block") {
18746
18822
  return {
18747
18823
  block: true,
@@ -18934,7 +19010,7 @@ async function executeStopHooks(ctx, config, extendedConfig) {
18934
19010
  }
18935
19011
  if (result.stdout) {
18936
19012
  try {
18937
- const output = JSON.parse(result.stdout);
19013
+ const output = JSON.parse(result.stdout || "{}");
18938
19014
  if (output.stop_hook_active !== undefined) {
18939
19015
  stopHookActiveState.set(ctx.sessionId, output.stop_hook_active);
18940
19016
  }
@@ -18991,7 +19067,7 @@ async function executePreCompactHooks(ctx, config, extendedConfig) {
18991
19067
  }
18992
19068
  if (result.stdout) {
18993
19069
  try {
18994
- const output = JSON.parse(result.stdout);
19070
+ const output = JSON.parse(result.stdout || "{}");
18995
19071
  if (output.hookSpecificOutput?.additionalContext) {
18996
19072
  collectedContext.push(...output.hookSpecificOutput.additionalContext);
18997
19073
  } else if (output.context) {
@@ -19194,6 +19270,9 @@ ${result.inputLines ?? ""}`,
19194
19270
  }
19195
19271
  },
19196
19272
  "tool.execute.after": async (input, output) => {
19273
+ if (!output) {
19274
+ return;
19275
+ }
19197
19276
  const claudeConfig = await loadClaudeHooksConfig();
19198
19277
  const extendedConfig = await loadPluginExtendedConfig();
19199
19278
  const cachedInput = getToolInput(input.sessionID, input.tool, input.callID) || {};
@@ -20064,7 +20143,81 @@ You ARE the planner. Your job: create bulletproof work plans.
20064
20143
  - External library APIs and constraints
20065
20144
  - Similar implementations in OSS (via librarian)
20066
20145
 
20067
- **NEVER plan blind. Context first, plan second.**`;
20146
+ **NEVER plan blind. Context first, plan second.**
20147
+
20148
+ ---
20149
+
20150
+ ## MANDATORY OUTPUT: PARALLEL TASK GRAPH + TODO LIST
20151
+
20152
+ **YOUR PRIMARY OUTPUT IS A PARALLEL EXECUTION TASK GRAPH.**
20153
+
20154
+ When you finalize a plan, you MUST structure it for maximum parallel execution:
20155
+
20156
+ ### 1. Parallel Execution Waves (REQUIRED)
20157
+
20158
+ Analyze task dependencies and group independent tasks into parallel waves:
20159
+
20160
+ \`\`\`
20161
+ Wave 1 (Start Immediately - No Dependencies):
20162
+ \u251C\u2500\u2500 Task 1: [description] \u2192 category: X, skills: [a, b]
20163
+ \u2514\u2500\u2500 Task 4: [description] \u2192 category: Y, skills: [c]
20164
+
20165
+ Wave 2 (After Wave 1 Completes):
20166
+ \u251C\u2500\u2500 Task 2: [depends: 1] \u2192 category: X, skills: [a]
20167
+ \u251C\u2500\u2500 Task 3: [depends: 1] \u2192 category: Z, skills: [d]
20168
+ \u2514\u2500\u2500 Task 5: [depends: 4] \u2192 category: Y, skills: [c]
20169
+
20170
+ Wave 3 (After Wave 2 Completes):
20171
+ \u2514\u2500\u2500 Task 6: [depends: 2, 3] \u2192 category: X, skills: [a, b]
20172
+
20173
+ Critical Path: Task 1 \u2192 Task 2 \u2192 Task 6
20174
+ Estimated Parallel Speedup: ~40% faster than sequential
20175
+ \`\`\`
20176
+
20177
+ ### 2. Dependency Matrix (REQUIRED)
20178
+
20179
+ | Task | Depends On | Blocks | Can Parallelize With |
20180
+ |------|------------|--------|---------------------|
20181
+ | 1 | None | 2, 3 | 4 |
20182
+ | 2 | 1 | 6 | 3, 5 |
20183
+ | 3 | 1 | 6 | 2, 5 |
20184
+ | 4 | None | 5 | 1 |
20185
+ | 5 | 4 | None | 2, 3 |
20186
+ | 6 | 2, 3 | None | None (final) |
20187
+
20188
+ ### 3. TODO List Structure (REQUIRED)
20189
+
20190
+ Each TODO item MUST include:
20191
+
20192
+ \`\`\`markdown
20193
+ - [ ] N. [Task Title]
20194
+
20195
+ **What to do**: [Clear steps]
20196
+
20197
+ **Dependencies**: [Task numbers this depends on] | None
20198
+ **Blocks**: [Task numbers that depend on this]
20199
+ **Parallel Group**: Wave N (with Tasks X, Y)
20200
+
20201
+ **Recommended Agent Profile**:
20202
+ - **Category**: \`[visual-engineering | ultrabrain | artistry | quick | unspecified-low | unspecified-high | writing]\`
20203
+ - **Skills**: [\`skill-1\`, \`skill-2\`]
20204
+
20205
+ **Acceptance Criteria**: [Verifiable conditions]
20206
+ \`\`\`
20207
+
20208
+ ### 4. Agent Dispatch Summary (REQUIRED)
20209
+
20210
+ | Wave | Tasks | Dispatch Command |
20211
+ |------|-------|------------------|
20212
+ | 1 | 1, 4 | \`delegate_task(category="...", load_skills=[...], run_in_background=true)\` \xD7 2 |
20213
+ | 2 | 2, 3, 5 | \`delegate_task(...)\` \xD7 3 after Wave 1 completes |
20214
+ | 3 | 6 | \`delegate_task(...)\` final integration |
20215
+
20216
+ **WHY PARALLEL TASK GRAPH IS MANDATORY:**
20217
+ - Orchestrator (Sisyphus) executes tasks in parallel waves
20218
+ - Independent tasks run simultaneously via background agents
20219
+ - Proper dependency tracking prevents race conditions
20220
+ - Category + skills ensure optimal model routing per task`;
20068
20221
  function isPlannerAgent(agentName) {
20069
20222
  if (!agentName)
20070
20223
  return false;
@@ -20169,52 +20322,52 @@ delegate_task(agent="oracle", prompt="Review my approach: [describe plan]")
20169
20322
  YOU MUST LEVERAGE ALL AVAILABLE AGENTS / **CATEGORY + SKILLS** TO THEIR FULLEST POTENTIAL.
20170
20323
  TELL THE USER WHAT AGENTS YOU WILL LEVERAGE NOW TO SATISFY USER'S REQUEST.
20171
20324
 
20172
- ## MANDATORY: PROMETHEUS AGENT INVOCATION (NON-NEGOTIABLE)
20325
+ ## MANDATORY: PLAN AGENT INVOCATION (NON-NEGOTIABLE)
20173
20326
 
20174
- **YOU MUST ALWAYS INVOKE PROMETHEUS (THE PLANNER) FOR ANY NON-TRIVIAL TASK.**
20327
+ **YOU MUST ALWAYS INVOKE THE PLAN AGENT FOR ANY NON-TRIVIAL TASK.**
20175
20328
 
20176
20329
  | Condition | Action |
20177
20330
  |-----------|--------|
20178
- | Task has 2+ steps | MUST call Prometheus |
20179
- | Task scope unclear | MUST call Prometheus |
20180
- | Implementation required | MUST call Prometheus |
20181
- | Architecture decision needed | MUST call Prometheus |
20331
+ | Task has 2+ steps | MUST call plan agent |
20332
+ | Task scope unclear | MUST call plan agent |
20333
+ | Implementation required | MUST call plan agent |
20334
+ | Architecture decision needed | MUST call plan agent |
20182
20335
 
20183
20336
  \`\`\`
20184
- delegate_task(subagent_type="prometheus", prompt="<gathered context + user request>")
20337
+ delegate_task(subagent_type="plan", prompt="<gathered context + user request>")
20185
20338
  \`\`\`
20186
20339
 
20187
- **WHY PROMETHEUS IS MANDATORY:**
20188
- - Prometheus analyzes dependencies and parallel execution opportunities
20189
- - Prometheus recommends CATEGORY + SKILLS for each task (in TL;DR + per-task)
20190
- - Prometheus ensures nothing is missed with structured work plans
20340
+ **WHY PLAN AGENT IS MANDATORY:**
20341
+ - Plan agent analyzes dependencies and parallel execution opportunities
20342
+ - Plan agent outputs a **parallel task graph** with waves and dependencies
20343
+ - Plan agent provides structured TODO list with category + skills per task
20191
20344
  - YOU are an orchestrator, NOT an implementer
20192
20345
 
20193
- ### SESSION CONTINUITY WITH PROMETHEUS (CRITICAL)
20346
+ ### SESSION CONTINUITY WITH PLAN AGENT (CRITICAL)
20194
20347
 
20195
- **Prometheus returns a session_id. USE IT for follow-up interactions.**
20348
+ **Plan agent returns a session_id. USE IT for follow-up interactions.**
20196
20349
 
20197
20350
  | Scenario | Action |
20198
20351
  |----------|--------|
20199
- | Prometheus asks clarifying questions | \`delegate_task(session_id="{returned_session_id}", prompt="<your answer>")\` |
20352
+ | Plan agent asks clarifying questions | \`delegate_task(session_id="{returned_session_id}", prompt="<your answer>")\` |
20200
20353
  | Need to refine the plan | \`delegate_task(session_id="{returned_session_id}", prompt="Please adjust: <feedback>")\` |
20201
20354
  | Plan needs more detail | \`delegate_task(session_id="{returned_session_id}", prompt="Add more detail to Task N")\` |
20202
20355
 
20203
20356
  **WHY SESSION_ID IS CRITICAL:**
20204
- - Prometheus retains FULL conversation context
20357
+ - Plan agent retains FULL conversation context
20205
20358
  - No repeated exploration or context gathering
20206
20359
  - Saves 70%+ tokens on follow-ups
20207
20360
  - Maintains interview continuity until plan is finalized
20208
20361
 
20209
20362
  \`\`\`
20210
20363
  // WRONG: Starting fresh loses all context
20211
- delegate_task(subagent_type="prometheus", prompt="Here's more info...")
20364
+ delegate_task(subagent_type="plan", prompt="Here's more info...")
20212
20365
 
20213
20366
  // CORRECT: Resume preserves everything
20214
20367
  delegate_task(session_id="ses_abc123", prompt="Here's my answer to your question: ...")
20215
20368
  \`\`\`
20216
20369
 
20217
- **FAILURE TO CALL PROMETHEUS = INCOMPLETE WORK.**
20370
+ **FAILURE TO CALL PLAN AGENT = INCOMPLETE WORK.**
20218
20371
 
20219
20372
  ---
20220
20373
 
@@ -20226,7 +20379,7 @@ delegate_task(session_id="ses_abc123", prompt="Here's my answer to your question
20226
20379
  |-----------|--------|-----|
20227
20380
  | Codebase exploration | delegate_task(subagent_type="explore", run_in_background=true) | Parallel, context-efficient |
20228
20381
  | Documentation lookup | delegate_task(subagent_type="librarian", run_in_background=true) | Specialized knowledge |
20229
- | Planning | delegate_task(subagent_type="plan") | Structured work breakdown |
20382
+ | Planning | delegate_task(subagent_type="plan") | Parallel task graph + structured TODO list |
20230
20383
  | Architecture/Debugging | delegate_task(subagent_type="oracle") | High-IQ reasoning |
20231
20384
  | Implementation | delegate_task(category="...", load_skills=[...]) | Domain-optimized models |
20232
20385
 
@@ -20286,20 +20439,20 @@ delegate_task(..., run_in_background=true) // task_id_3
20286
20439
  delegate_task(subagent_type="librarian", run_in_background=true, prompt="...")
20287
20440
  \`\`\`
20288
20441
 
20289
- 2. **INVOKE PROMETHEUS** (MANDATORY for non-trivial tasks):
20442
+ 2. **INVOKE PLAN AGENT** (MANDATORY for non-trivial tasks):
20290
20443
  \`\`\`
20291
- result = delegate_task(subagent_type="prometheus", prompt="<context + request>")
20444
+ result = delegate_task(subagent_type="plan", prompt="<context + request>")
20292
20445
  // STORE the session_id for follow-ups!
20293
- prometheus_session_id = result.session_id
20446
+ plan_session_id = result.session_id
20294
20447
  \`\`\`
20295
20448
 
20296
- 3. **ITERATE WITH PROMETHEUS** (if clarification needed):
20449
+ 3. **ITERATE WITH PLAN AGENT** (if clarification needed):
20297
20450
  \`\`\`
20298
20451
  // Use session_id to continue the conversation
20299
- delegate_task(session_id=prometheus_session_id, prompt="<answer to Prometheus's question>")
20452
+ delegate_task(session_id=plan_session_id, prompt="<answer to plan agent's question>")
20300
20453
  \`\`\`
20301
20454
 
20302
- 4. **EXECUTE VIA DELEGATION** (category + skills from Prometheus's plan):
20455
+ 4. **EXECUTE VIA DELEGATION** (category + skills from plan agent's output):
20303
20456
  \`\`\`
20304
20457
  delegate_task(category="...", load_skills=[...], prompt="<task from plan>")
20305
20458
  \`\`\`
@@ -20378,9 +20531,9 @@ Write these criteria explicitly. Share with user if scope is non-trivial.
20378
20531
  THE USER ASKED FOR X. DELIVER EXACTLY X. NOT A SUBSET. NOT A DEMO. NOT A STARTING POINT.
20379
20532
 
20380
20533
  1. EXPLORES + LIBRARIANS (background)
20381
- 2. GATHER -> delegate_task(subagent_type="prometheus", prompt="<context + request>")
20382
- 3. ITERATE WITH PROMETHEUS (session_id resume) UNTIL PLAN IS FINALIZED
20383
- 4. WORK BY DELEGATING TO CATEGORY + SKILLS AGENTS (following Prometheus's plan)
20534
+ 2. GATHER -> delegate_task(subagent_type="plan", prompt="<context + request>")
20535
+ 3. ITERATE WITH PLAN AGENT (session_id resume) UNTIL PLAN IS FINALIZED
20536
+ 4. WORK BY DELEGATING TO CATEGORY + SKILLS AGENTS (following plan agent's parallel task graph)
20384
20537
 
20385
20538
  NOW.
20386
20539
 
@@ -20453,7 +20606,8 @@ function createKeywordDetectorHook(ctx, collector) {
20453
20606
  return;
20454
20607
  }
20455
20608
  const currentAgent = getSessionAgent(input.sessionID) ?? input.agent;
20456
- let detectedKeywords = detectKeywordsWithType(removeCodeBlocks2(promptText), currentAgent);
20609
+ const cleanText = removeSystemReminders(promptText);
20610
+ let detectedKeywords = detectKeywordsWithType(removeCodeBlocks2(cleanText), currentAgent);
20457
20611
  if (isPlannerAgent(currentAgent)) {
20458
20612
  detectedKeywords = detectedKeywords.filter((k) => k.type !== "ultrawork");
20459
20613
  }
@@ -21577,6 +21731,9 @@ async function loadMcpJsonFromDir(skillDir) {
21577
21731
  function parseAllowedTools(allowedTools) {
21578
21732
  if (!allowedTools)
21579
21733
  return;
21734
+ if (Array.isArray(allowedTools)) {
21735
+ return allowedTools.map((t) => t.trim()).filter(Boolean);
21736
+ }
21580
21737
  return allowedTools.split(/\s+/).filter(Boolean);
21581
21738
  }
21582
21739
  async function loadSkillFromPath(skillPath, resolvedPath, defaultName, scope) {
@@ -21744,6 +21901,14 @@ init_deep_merge();
21744
21901
  import { readFileSync as readFileSync21, existsSync as existsSync31 } from "fs";
21745
21902
  import { dirname as dirname7, resolve as resolve6, isAbsolute as isAbsolute2 } from "path";
21746
21903
  import { homedir as homedir10 } from "os";
21904
+ function parseAllowedToolsFromMetadata(allowedTools) {
21905
+ if (!allowedTools)
21906
+ return;
21907
+ if (Array.isArray(allowedTools)) {
21908
+ return allowedTools.map((t) => t.trim()).filter(Boolean);
21909
+ }
21910
+ return allowedTools.split(/\s+/).filter(Boolean);
21911
+ }
21747
21912
  var SCOPE_PRIORITY = {
21748
21913
  builtin: 1,
21749
21914
  config: 2,
@@ -21835,7 +22000,7 @@ $ARGUMENTS
21835
22000
  subtask: entry.subtask ?? fileMetadata.subtask,
21836
22001
  argumentHint: entry["argument-hint"] || fileMetadata["argument-hint"]
21837
22002
  };
21838
- const allowedTools = entry["allowed-tools"] || (fileMetadata["allowed-tools"] ? fileMetadata["allowed-tools"].split(/\s+/).filter(Boolean) : undefined);
22003
+ const allowedTools = entry["allowed-tools"] || (fileMetadata["allowed-tools"] ? parseAllowedToolsFromMetadata(fileMetadata["allowed-tools"]) : undefined);
21839
22004
  return {
21840
22005
  name,
21841
22006
  path: entry.from ? resolveFilePath2(entry.from, configDir) : undefined,
@@ -24617,7 +24782,7 @@ ${contextInfo}`;
24617
24782
  };
24618
24783
  }
24619
24784
  // src/hooks/atlas/index.ts
24620
- import { execSync } from "child_process";
24785
+ import { execSync as execSync2 } from "child_process";
24621
24786
  init_hook_message_injector();
24622
24787
  init_logger();
24623
24788
  init_system_directive();
@@ -24856,7 +25021,7 @@ function extractSessionIdFromOutput(output) {
24856
25021
  }
24857
25022
  function getGitDiffStats(directory) {
24858
25023
  try {
24859
- const output = execSync("git diff --numstat HEAD", {
25024
+ const output = execSync2("git diff --numstat HEAD", {
24860
25025
  cwd: directory,
24861
25026
  encoding: "utf-8",
24862
25027
  timeout: 5000,
@@ -24864,7 +25029,7 @@ function getGitDiffStats(directory) {
24864
25029
  }).trim();
24865
25030
  if (!output)
24866
25031
  return [];
24867
- const statusOutput = execSync("git status --porcelain", {
25032
+ const statusOutput = execSync2("git status --porcelain", {
24868
25033
  cwd: directory,
24869
25034
  encoding: "utf-8",
24870
25035
  timeout: 5000,
@@ -25161,6 +25326,9 @@ function createAtlasHook(ctx, options) {
25161
25326
  }
25162
25327
  },
25163
25328
  "tool.execute.after": async (input, output) => {
25329
+ if (!output) {
25330
+ return;
25331
+ }
25164
25332
  if (!isCallerOrchestrator(input.sessionID)) {
25165
25333
  return;
25166
25334
  }
@@ -43589,7 +43757,10 @@ async function executeSync(args, toolContext, ctx) {
43589
43757
  const createResult = await ctx.client.session.create({
43590
43758
  body: {
43591
43759
  parentID: toolContext.sessionID,
43592
- title: `${args.description} (@${args.subagent_type} subagent)`
43760
+ title: `${args.description} (@${args.subagent_type} subagent)`,
43761
+ permission: [
43762
+ { permission: "question", action: "deny", pattern: "*" }
43763
+ ]
43593
43764
  },
43594
43765
  query: {
43595
43766
  directory: parentDirectory
@@ -43597,6 +43768,17 @@ async function executeSync(args, toolContext, ctx) {
43597
43768
  });
43598
43769
  if (createResult.error) {
43599
43770
  log(`[call_omo_agent] Session create error:`, createResult.error);
43771
+ const errorStr = String(createResult.error);
43772
+ if (errorStr.toLowerCase().includes("unauthorized")) {
43773
+ return `Error: Failed to create session (Unauthorized). This may be due to:
43774
+ 1. OAuth token restrictions (e.g., Claude Code credentials are restricted to Claude Code only)
43775
+ 2. Provider authentication issues
43776
+ 3. Session permission inheritance problems
43777
+
43778
+ Try using a different provider or API key authentication.
43779
+
43780
+ Original error: ${createResult.error}`;
43781
+ }
43600
43782
  return `Error: Failed to create session: ${createResult.error}`;
43601
43783
  }
43602
43784
  sessionID = createResult.data.id;
@@ -43837,7 +44019,10 @@ If the requested information is not found, clearly state what is missing.`;
43837
44019
  const createResult = await ctx.client.session.create({
43838
44020
  body: {
43839
44021
  parentID: toolContext.sessionID,
43840
- title: `look_at: ${args.goal.substring(0, 50)}`
44022
+ title: `look_at: ${args.goal.substring(0, 50)}`,
44023
+ permission: [
44024
+ { permission: "question", action: "deny", pattern: "*" }
44025
+ ]
43841
44026
  },
43842
44027
  query: {
43843
44028
  directory: parentDirectory
@@ -43845,6 +44030,17 @@ If the requested information is not found, clearly state what is missing.`;
43845
44030
  });
43846
44031
  if (createResult.error) {
43847
44032
  log(`[look_at] Session create error:`, createResult.error);
44033
+ const errorStr = String(createResult.error);
44034
+ if (errorStr.toLowerCase().includes("unauthorized")) {
44035
+ return `Error: Failed to create session (Unauthorized). This may be due to:
44036
+ 1. OAuth token restrictions (e.g., Claude Code credentials are restricted to Claude Code only)
44037
+ 2. Provider authentication issues
44038
+ 3. Session permission inheritance problems
44039
+
44040
+ Try using a different provider or API key authentication.
44041
+
44042
+ Original error: ${createResult.error}`;
44043
+ }
43848
44044
  return `Error: Failed to create session: ${createResult.error}`;
43849
44045
  }
43850
44046
  const sessionID = createResult.data.id;
@@ -44681,6 +44877,11 @@ To continue this session: session_id="${sessionID}"`;
44681
44877
  return `Cannot use subagent_type="${SISYPHUS_JUNIOR_AGENT}" directly. Use category parameter instead (e.g., ${categoryExamples}).
44682
44878
 
44683
44879
  Sisyphus-Junior is spawned automatically when you specify a category. Pick the appropriate category for your task domain.`;
44880
+ }
44881
+ if (isPlanAgent(agentName) && isPlanAgent(parentAgent)) {
44882
+ return `You are prometheus. You cannot delegate to prometheus via delegate_task.
44883
+
44884
+ Create the work plan directly - that's your job as the planning agent.`;
44684
44885
  }
44685
44886
  agentToUse = agentName;
44686
44887
  try {
@@ -44809,6 +45010,7 @@ To continue this session: session_id="${task.sessionID}"`;
44809
45010
  }
44810
45011
  });
44811
45012
  try {
45013
+ const allowDelegateTask = isPlanAgent(agentToUse);
44812
45014
  await client2.session.prompt({
44813
45015
  path: { id: sessionID },
44814
45016
  body: {
@@ -44816,7 +45018,7 @@ To continue this session: session_id="${task.sessionID}"`;
44816
45018
  system: systemContent,
44817
45019
  tools: {
44818
45020
  task: false,
44819
- delegate_task: false,
45021
+ delegate_task: allowDelegateTask,
44820
45022
  call_omo_agent: true,
44821
45023
  question: false
44822
45024
  },
@@ -52919,6 +53121,8 @@ call_omo_agent(subagent_type="librarian", prompt="Find OSS implementations of Z.
52919
53121
  - [Risk 2]: [Mitigation]
52920
53122
 
52921
53123
  ## Directives for Prometheus
53124
+
53125
+ ### Core Directives
52922
53126
  - MUST: [Required action]
52923
53127
  - MUST: [Required action]
52924
53128
  - MUST NOT: [Forbidden action]
@@ -52926,6 +53130,29 @@ call_omo_agent(subagent_type="librarian", prompt="Find OSS implementations of Z.
52926
53130
  - PATTERN: Follow \`[file:lines]\`
52927
53131
  - TOOL: Use \`[specific tool]\` for [purpose]
52928
53132
 
53133
+ ### QA/Acceptance Criteria Directives (MANDATORY)
53134
+ > **ZERO USER INTERVENTION PRINCIPLE**: All acceptance criteria MUST be executable by agents.
53135
+
53136
+ - MUST: Write acceptance criteria as executable commands (curl, bun test, playwright actions)
53137
+ - MUST: Include exact expected outputs, not vague descriptions
53138
+ - MUST: Specify verification tool for each deliverable type (playwright for UI, curl for API, etc.)
53139
+ - MUST NOT: Create criteria requiring "user manually tests..."
53140
+ - MUST NOT: Create criteria requiring "user visually confirms..."
53141
+ - MUST NOT: Create criteria requiring "user clicks/interacts..."
53142
+ - MUST NOT: Use placeholders without concrete examples (bad: "[endpoint]", good: "/api/users")
53143
+
53144
+ Example of GOOD acceptance criteria:
53145
+ \`\`\`
53146
+ curl -s http://localhost:3000/api/health | jq '.status'
53147
+ # Assert: Output is "ok"
53148
+ \`\`\`
53149
+
53150
+ Example of BAD acceptance criteria (FORBIDDEN):
53151
+ \`\`\`
53152
+ User opens browser and checks if the page loads correctly.
53153
+ User confirms the button works as expected.
53154
+ \`\`\`
53155
+
52929
53156
  ## Recommended Approach
52930
53157
  [1-2 sentence summary of how to proceed]
52931
53158
  \`\`\`
@@ -52952,12 +53179,16 @@ call_omo_agent(subagent_type="librarian", prompt="Find OSS implementations of Z.
52952
53179
  - Ask generic questions ("What's the scope?")
52953
53180
  - Proceed without addressing ambiguity
52954
53181
  - Make assumptions about user's codebase
53182
+ - Suggest acceptance criteria requiring user intervention ("user manually tests", "user confirms", "user clicks")
53183
+ - Leave QA/acceptance criteria vague or placeholder-heavy
52955
53184
 
52956
53185
  **ALWAYS**:
52957
53186
  - Classify intent FIRST
52958
53187
  - Be specific ("Should this change UserService only, or also AuthService?")
52959
53188
  - Explore before asking (for Build/Research intents)
52960
53189
  - Provide actionable directives for Prometheus
53190
+ - Include QA automation directives in every output
53191
+ - Ensure acceptance criteria are agent-executable (commands, not human actions)
52961
53192
  `;
52962
53193
  var metisRestrictions = createAgentToolRestrictions([
52963
53194
  "write",
@@ -55714,27 +55945,37 @@ Each TODO follows RED-GREEN-REFACTOR:
55714
55945
  - Example: Create \`src/__tests__/example.test.ts\`
55715
55946
  - Verify: \`bun test\` \u2192 1 test passes
55716
55947
 
55717
- ### If Manual QA Only
55948
+ ### If Automated Verification Only (NO User Intervention)
55718
55949
 
55719
- **CRITICAL**: Without automated tests, manual verification MUST be exhaustive.
55950
+ > **CRITICAL PRINCIPLE: ZERO USER INTERVENTION**
55951
+ >
55952
+ > **NEVER** create acceptance criteria that require:
55953
+ > - "User manually tests..." / "\uC0AC\uC6A9\uC790\uAC00 \uC9C1\uC811 \uD14C\uC2A4\uD2B8..."
55954
+ > - "User visually confirms..." / "\uC0AC\uC6A9\uC790\uAC00 \uB208\uC73C\uB85C \uD655\uC778..."
55955
+ > - "User interacts with..." / "\uC0AC\uC6A9\uC790\uAC00 \uC9C1\uC811 \uC870\uC791..."
55956
+ > - "Ask user to verify..." / "\uC0AC\uC6A9\uC790\uC5D0\uAC8C \uD655\uC778 \uC694\uCCAD..."
55957
+ > - ANY step that requires a human to perform an action
55958
+ >
55959
+ > **ALL verification MUST be automated and executable by the agent.**
55960
+ > If a verification cannot be automated, find an automated alternative or explicitly note it as a known limitation.
55720
55961
 
55721
- Each TODO includes detailed verification procedures:
55962
+ Each TODO includes EXECUTABLE verification procedures that agents can run directly:
55722
55963
 
55723
55964
  **By Deliverable Type:**
55724
55965
 
55725
- | Type | Verification Tool | Procedure |
55726
- |------|------------------|-----------|
55727
- | **Frontend/UI** | Playwright browser | Navigate, interact, screenshot |
55728
- | **TUI/CLI** | interactive_bash (tmux) | Run command, verify output |
55729
- | **API/Backend** | curl / httpie | Send request, verify response |
55730
- | **Library/Module** | Node/Python REPL | Import, call, verify |
55731
- | **Config/Infra** | Shell commands | Apply, verify state |
55966
+ | Type | Verification Tool | Automated Procedure |
55967
+ |------|------------------|---------------------|
55968
+ | **Frontend/UI** | Playwright browser via playwright skill | Agent navigates, clicks, screenshots, asserts DOM state |
55969
+ | **TUI/CLI** | interactive_bash (tmux) | Agent runs command, captures output, validates expected strings |
55970
+ | **API/Backend** | curl / httpie via Bash | Agent sends request, parses response, validates JSON fields |
55971
+ | **Library/Module** | Node/Python REPL via Bash | Agent imports, calls function, compares output |
55972
+ | **Config/Infra** | Shell commands via Bash | Agent applies config, runs state check, validates output |
55732
55973
 
55733
- **Evidence Required:**
55734
- - Commands run with actual output
55735
- - Screenshots for visual changes
55736
- - Response bodies for API changes
55737
- - Terminal output for CLI changes
55974
+ **Evidence Requirements (Agent-Executable):**
55975
+ - Command output captured and compared against expected patterns
55976
+ - Screenshots saved to .sisyphus/evidence/ for visual verification
55977
+ - JSON response fields validated with specific assertions
55978
+ - Exit codes checked (0 = success)
55738
55979
 
55739
55980
  ---
55740
55981
 
@@ -55844,53 +56085,76 @@ Parallel Speedup: ~40% faster than sequential
55844
56085
 
55845
56086
  **Acceptance Criteria**:
55846
56087
 
55847
- > CRITICAL: Acceptance = EXECUTION, not just "it should work".
55848
- > The executor MUST run these commands and verify output.
56088
+ > **CRITICAL: AGENT-EXECUTABLE VERIFICATION ONLY**
56089
+ >
56090
+ > - Acceptance = EXECUTION by the agent, not "user checks if it works"
56091
+ > - Every criterion MUST be verifiable by running a command or using a tool
56092
+ > - NO steps like "user opens browser", "user clicks", "user confirms"
56093
+ > - If you write "[placeholder]" - REPLACE IT with actual values based on task context
55849
56094
 
55850
56095
  **If TDD (tests enabled):**
55851
- - [ ] Test file created: \`[path].test.ts\`
55852
- - [ ] Test covers: [specific scenario]
55853
- - [ ] \`bun test [file]\` \u2192 PASS (N tests, 0 failures)
55854
-
55855
- **Manual Execution Verification (ALWAYS include, even with tests):**
55856
-
55857
- *Choose based on deliverable type:*
55858
-
55859
- **For Frontend/UI changes:**
55860
- - [ ] Using playwright browser automation:
55861
- - Navigate to: \`http://localhost:[port]/[path]\`
55862
- - Action: [click X, fill Y, scroll to Z]
55863
- - Verify: [visual element appears, animation completes, state changes]
55864
- - Screenshot: Save evidence to \`.sisyphus/evidence/[task-id]-[step].png\`
55865
-
55866
- **For TUI/CLI changes:**
55867
- - [ ] Using interactive_bash (tmux session):
55868
- - Command: \`[exact command to run]\`
55869
- - Input sequence: [if interactive, list inputs]
55870
- - Expected output contains: \`[expected string or pattern]\`
55871
- - Exit code: [0 for success, specific code if relevant]
55872
-
55873
- **For API/Backend changes:**
55874
- - [ ] Request: \`curl -X [METHOD] http://localhost:[port]/[endpoint] -H "Content-Type: application/json" -d '[body]'\`
55875
- - [ ] Response status: [200/201/etc]
55876
- - [ ] Response body contains: \`{"key": "expected_value"}\`
55877
-
55878
- **For Library/Module changes:**
55879
- - [ ] REPL verification:
55880
- \`\`\`
55881
- > import { [function] } from '[module]'
55882
- > [function]([args])
55883
- Expected: [output]
55884
- \`\`\`
55885
-
55886
- **For Config/Infra changes:**
55887
- - [ ] Apply: \`[command to apply config]\`
55888
- - [ ] Verify state: \`[command to check state]\` \u2192 \`[expected output]\`
55889
-
55890
- **Evidence Required:**
55891
- - [ ] Command output captured (copy-paste actual terminal output)
55892
- - [ ] Screenshot saved (for visual changes)
55893
- - [ ] Response body logged (for API changes)
56096
+ - [ ] Test file created: src/auth/login.test.ts
56097
+ - [ ] Test covers: successful login returns JWT token
56098
+ - [ ] bun test src/auth/login.test.ts \u2192 PASS (3 tests, 0 failures)
56099
+
56100
+ **Automated Verification (ALWAYS include, choose by deliverable type):**
56101
+
56102
+ **For Frontend/UI changes** (using playwright skill):
56103
+ \\\`\\\`\\\`
56104
+ # Agent executes via playwright browser automation:
56105
+ 1. Navigate to: http://localhost:3000/login
56106
+ 2. Fill: input[name="email"] with "test@example.com"
56107
+ 3. Fill: input[name="password"] with "password123"
56108
+ 4. Click: button[type="submit"]
56109
+ 5. Wait for: selector ".dashboard-welcome" to be visible
56110
+ 6. Assert: text "Welcome back" appears on page
56111
+ 7. Screenshot: .sisyphus/evidence/task-1-login-success.png
56112
+ \\\`\\\`\\\`
56113
+
56114
+ **For TUI/CLI changes** (using interactive_bash):
56115
+ \\\`\\\`\\\`
56116
+ # Agent executes via tmux session:
56117
+ 1. Command: ./my-cli --config test.yaml
56118
+ 2. Wait for: "Configuration loaded" in output
56119
+ 3. Send keys: "q" to quit
56120
+ 4. Assert: Exit code 0
56121
+ 5. Assert: Output contains "Goodbye"
56122
+ \\\`\\\`\\\`
56123
+
56124
+ **For API/Backend changes** (using Bash curl):
56125
+ \\\`\\\`\\\`bash
56126
+ # Agent runs:
56127
+ curl -s -X POST http://localhost:8080/api/users \\
56128
+ -H "Content-Type: application/json" \\
56129
+ -d '{"email":"new@test.com","name":"Test User"}' \\
56130
+ | jq '.id'
56131
+ # Assert: Returns non-empty UUID
56132
+ # Assert: HTTP status 201
56133
+ \\\`\\\`\\\`
56134
+
56135
+ **For Library/Module changes** (using Bash node/bun):
56136
+ \\\`\\\`\\\`bash
56137
+ # Agent runs:
56138
+ bun -e "import { validateEmail } from './src/utils/validate'; console.log(validateEmail('test@example.com'))"
56139
+ # Assert: Output is "true"
56140
+
56141
+ bun -e "import { validateEmail } from './src/utils/validate'; console.log(validateEmail('invalid'))"
56142
+ # Assert: Output is "false"
56143
+ \\\`\\\`\\\`
56144
+
56145
+ **For Config/Infra changes** (using Bash):
56146
+ \\\`\\\`\\\`bash
56147
+ # Agent runs:
56148
+ docker compose up -d
56149
+ # Wait 5s for containers
56150
+ docker compose ps --format json | jq '.[].State'
56151
+ # Assert: All states are "running"
56152
+ \\\`\\\`\\\`
56153
+
56154
+ **Evidence to Capture:**
56155
+ - [ ] Terminal output from verification commands (actual output, not expected)
56156
+ - [ ] Screenshot files in .sisyphus/evidence/ for UI changes
56157
+ - [ ] JSON response bodies for API changes
55894
56158
 
55895
56159
  **Commit**: YES | NO (groups with N)
55896
56160
  - Message: \`type(scope): desc\`
@@ -56292,7 +56556,20 @@ var OhMyOpenCodePlugin = async (ctx) => {
56292
56556
  const toolOutputTruncator = isHookEnabled("tool-output-truncator") ? createToolOutputTruncatorHook(ctx, {
56293
56557
  experimental: pluginConfig.experimental
56294
56558
  }) : null;
56295
- const directoryAgentsInjector = isHookEnabled("directory-agents-injector") ? createDirectoryAgentsInjectorHook(ctx) : null;
56559
+ let directoryAgentsInjector = null;
56560
+ if (isHookEnabled("directory-agents-injector")) {
56561
+ const currentVersion = getOpenCodeVersion();
56562
+ const hasNativeSupport = currentVersion !== null && isOpenCodeVersionAtLeast(OPENCODE_NATIVE_AGENTS_INJECTION_VERSION);
56563
+ if (hasNativeSupport) {
56564
+ console.warn(`[oh-my-opencode] directory-agents-injector hook auto-disabled: ` + `OpenCode ${currentVersion} has native AGENTS.md support (>= ${OPENCODE_NATIVE_AGENTS_INJECTION_VERSION})`);
56565
+ log("directory-agents-injector auto-disabled due to native OpenCode support", {
56566
+ currentVersion,
56567
+ nativeVersion: OPENCODE_NATIVE_AGENTS_INJECTION_VERSION
56568
+ });
56569
+ } else {
56570
+ directoryAgentsInjector = createDirectoryAgentsInjectorHook(ctx);
56571
+ }
56572
+ }
56296
56573
  const directoryReadmeInjector = isHookEnabled("directory-readme-injector") ? createDirectoryReadmeInjectorHook(ctx) : null;
56297
56574
  const emptyTaskResponseDetector = isHookEnabled("empty-task-response-detector") ? createEmptyTaskResponseDetectorHook(ctx) : null;
56298
56575
  const thinkMode = isHookEnabled("think-mode") ? createThinkModeHook() : null;
@@ -56453,13 +56730,20 @@ var OhMyOpenCodePlugin = async (ctx) => {
56453
56730
  }
56454
56731
  const message = output.message;
56455
56732
  if (firstMessageVariantGate.shouldOverride(input.sessionID)) {
56456
- const variant = resolveAgentVariant(pluginConfig, input.agent);
56733
+ const variant = input.model && input.agent ? resolveVariantForModel(pluginConfig, input.agent, input.model) : resolveAgentVariant(pluginConfig, input.agent);
56457
56734
  if (variant !== undefined) {
56458
56735
  message.variant = variant;
56459
56736
  }
56460
56737
  firstMessageVariantGate.markApplied(input.sessionID);
56461
56738
  } else {
56462
- applyAgentVariant(pluginConfig, input.agent, message);
56739
+ if (input.model && input.agent && message.variant === undefined) {
56740
+ const variant = resolveVariantForModel(pluginConfig, input.agent, input.model);
56741
+ if (variant !== undefined) {
56742
+ message.variant = variant;
56743
+ }
56744
+ } else {
56745
+ applyAgentVariant(pluginConfig, input.agent, message);
56746
+ }
56463
56747
  }
56464
56748
  await keywordDetector?.["chat.message"]?.(input, output);
56465
56749
  await claudeCodeHooks["chat.message"]?.(input, output);
@@ -56636,6 +56920,9 @@ var OhMyOpenCodePlugin = async (ctx) => {
56636
56920
  }
56637
56921
  },
56638
56922
  "tool.execute.after": async (input, output) => {
56923
+ if (!output) {
56924
+ return;
56925
+ }
56639
56926
  await claudeCodeHooks["tool.execute.after"](input, output);
56640
56927
  await toolOutputTruncator?.["tool.execute.after"](input, output);
56641
56928
  await contextWindowMonitor?.["tool.execute.after"](input, output);