opencode-athena 0.2.0 → 0.4.0

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.
@@ -71,19 +71,66 @@ function handleSessionError(event, tracker) {
71
71
  }
72
72
 
73
73
  // src/plugin/hooks/tool-hooks.ts
74
- function createToolHooks(_tracker, _config) {
74
+ var GIT_WRITE_COMMANDS = [
75
+ "git commit",
76
+ "git push",
77
+ "git checkout -b",
78
+ "git branch ",
79
+ "git switch -c",
80
+ "git switch --create",
81
+ "git merge",
82
+ "git rebase",
83
+ "git cherry-pick",
84
+ "git stash",
85
+ "git tag",
86
+ "git reset",
87
+ "gh pr create",
88
+ "gh pr edit",
89
+ "gh pr merge",
90
+ "gh pr close",
91
+ "gh pr review",
92
+ "gh issue create",
93
+ "gh issue edit",
94
+ "gh issue close",
95
+ "gh release create",
96
+ "gh release edit",
97
+ "gh release delete"
98
+ ];
99
+ function getBashCommand(metadata) {
100
+ if (!metadata || typeof metadata !== "object") {
101
+ return "";
102
+ }
103
+ const cmd = metadata.command;
104
+ return typeof cmd === "string" ? cmd : "";
105
+ }
106
+ function containsGitWriteCommand(command) {
107
+ const normalized = command.trim().toLowerCase();
108
+ const segments = normalized.split(/[;&|]+/).map((s) => s.trim());
109
+ return segments.some(
110
+ (segment) => GIT_WRITE_COMMANDS.some((gitCmd) => segment.startsWith(gitCmd.toLowerCase()))
111
+ );
112
+ }
113
+ function createToolHooks(_tracker, config) {
75
114
  return {
76
115
  /**
77
116
  * Called before a tool executes
78
- * Can modify args or throw to block execution
79
117
  */
80
118
  before: async (_input, _output) => {
119
+ return;
81
120
  },
82
121
  /**
83
122
  * Called after a tool executes
84
- * Can modify output or append messages
85
123
  */
86
- after: async (_input, _output) => {
124
+ after: async (input, output) => {
125
+ if (config.features.autoGitOperations) {
126
+ return;
127
+ }
128
+ if (input.tool === "bash") {
129
+ const command = getBashCommand(output.metadata);
130
+ if (containsGitWriteCommand(command)) {
131
+ output.output += "\n\n\u26A0\uFE0F ATHENA GIT OPERATIONS POLICY REMINDER:\nGit operations should only be performed when explicitly requested by the user.\nIf this command was run automatically (not requested by the user), please:\n1. Ask the user before proceeding with further git operations\n2. Use athena_update_status() to track story progress instead of git commits\n\nTo enable automatic git operations, set features.autoGitOperations=true in athena.json";
132
+ }
133
+ }
87
134
  }
88
135
  };
89
136
  }
@@ -134,7 +181,8 @@ var DEFAULTS = {
134
181
  notifications: true,
135
182
  contextMonitor: true,
136
183
  commentChecker: true,
137
- lspTools: true
184
+ lspTools: true,
185
+ autoGitOperations: false
138
186
  },
139
187
  /** Default MCPs enabled */
140
188
  mcps: {
@@ -1361,6 +1409,11 @@ var SubscriptionSchema = z.object({
1361
1409
  google: z.object({
1362
1410
  enabled: z.boolean(),
1363
1411
  authMethod: z.enum(["antigravity", "personal", "api", "none"])
1412
+ }),
1413
+ githubCopilot: z.object({
1414
+ enabled: z.boolean(),
1415
+ plan: z.enum(["free", "pro", "pro-plus", "business", "enterprise", "none"]),
1416
+ enabledModels: z.array(z.string()).optional()
1364
1417
  })
1365
1418
  });
1366
1419
  var BmadConfigSchema = z.object({
@@ -1375,20 +1428,47 @@ var FeaturesSchema = z.object({
1375
1428
  notifications: z.boolean(),
1376
1429
  contextMonitor: z.boolean(),
1377
1430
  commentChecker: z.boolean(),
1378
- lspTools: z.boolean()
1431
+ lspTools: z.boolean(),
1432
+ autoGitOperations: z.boolean().default(false)
1379
1433
  });
1380
1434
  var McpsSchema = z.object({
1381
1435
  context7: z.boolean(),
1382
1436
  exa: z.boolean(),
1383
1437
  grepApp: z.boolean()
1384
1438
  });
1439
+ var ThinkingLevelSchema = z.enum(["off", "low", "medium", "high"]);
1440
+ var AgentSettingsSchema = z.object({
1441
+ temperature: z.number().min(0).max(1).optional(),
1442
+ thinkingLevel: ThinkingLevelSchema.optional()
1443
+ });
1444
+ var CustomModelDefinitionSchema = z.object({
1445
+ id: z.string(),
1446
+ name: z.string(),
1447
+ provider: z.enum(["anthropic", "openai", "google", "github-copilot"]),
1448
+ description: z.string().optional(),
1449
+ capabilities: z.object({
1450
+ thinking: z.boolean().optional(),
1451
+ contextWindow: z.number().optional(),
1452
+ supportsTemperature: z.boolean().optional()
1453
+ }).optional()
1454
+ });
1385
1455
  var ModelsSchema = z.object({
1386
1456
  sisyphus: z.string().describe("Model for main orchestrator agent"),
1387
1457
  oracle: z.string().describe("Model for debugging/reasoning agent"),
1388
1458
  librarian: z.string().describe("Model for research/documentation agent"),
1389
1459
  frontend: z.string().optional().describe("Model for UI/UX agent"),
1390
1460
  documentWriter: z.string().optional().describe("Model for documentation generation agent"),
1391
- multimodalLooker: z.string().optional().describe("Model for image analysis agent")
1461
+ multimodalLooker: z.string().optional().describe("Model for image analysis agent"),
1462
+ settings: z.object({
1463
+ sisyphus: AgentSettingsSchema.optional(),
1464
+ oracle: AgentSettingsSchema.optional(),
1465
+ librarian: AgentSettingsSchema.optional(),
1466
+ frontend: AgentSettingsSchema.optional(),
1467
+ documentWriter: AgentSettingsSchema.optional(),
1468
+ multimodalLooker: AgentSettingsSchema.optional(),
1469
+ overrides: z.record(z.string(), AgentSettingsSchema).optional()
1470
+ }).optional(),
1471
+ custom: z.array(CustomModelDefinitionSchema).optional()
1392
1472
  });
1393
1473
  var AthenaConfigSchema = z.object({
1394
1474
  $schema: z.string().optional(),
@@ -1520,22 +1600,37 @@ function validatePartialConfig(config, filePath) {
1520
1600
  authMethod: isValidAuthMethod(google.authMethod) ? google.authMethod : "none"
1521
1601
  };
1522
1602
  }
1603
+ if (subs.githubCopilot && typeof subs.githubCopilot === "object") {
1604
+ const copilot = subs.githubCopilot;
1605
+ result.subscriptions.githubCopilot = {
1606
+ enabled: typeof copilot.enabled === "boolean" ? copilot.enabled : false,
1607
+ plan: isValidCopilotPlan(copilot.plan) ? copilot.plan : "none",
1608
+ enabledModels: Array.isArray(copilot.enabledModels) ? copilot.enabledModels.filter((m) => typeof m === "string") : void 0
1609
+ };
1610
+ }
1523
1611
  }
1524
1612
  if ("models" in configObj && typeof configObj.models === "object") {
1525
1613
  const models = configObj.models;
1526
1614
  result.models = {};
1527
- for (const key of [
1615
+ const modelKeys = [
1528
1616
  "sisyphus",
1529
1617
  "oracle",
1530
1618
  "librarian",
1531
1619
  "frontend",
1532
1620
  "documentWriter",
1533
1621
  "multimodalLooker"
1534
- ]) {
1622
+ ];
1623
+ for (const key of modelKeys) {
1535
1624
  if (key in models && typeof models[key] === "string") {
1536
1625
  result.models[key] = models[key];
1537
1626
  }
1538
1627
  }
1628
+ if ("settings" in models && typeof models.settings === "object" && models.settings !== null) {
1629
+ result.models.settings = validateModelSettings(models.settings);
1630
+ }
1631
+ if ("custom" in models && Array.isArray(models.custom)) {
1632
+ result.models.custom = validateCustomModels(models.custom);
1633
+ }
1539
1634
  }
1540
1635
  if ("bmad" in configObj && typeof configObj.bmad === "object") {
1541
1636
  const bmad = configObj.bmad;
@@ -1584,9 +1679,104 @@ function isValidTier(value) {
1584
1679
  function isValidAuthMethod(value) {
1585
1680
  return typeof value === "string" && ["antigravity", "personal", "api", "none"].includes(value);
1586
1681
  }
1682
+ function isValidCopilotPlan(value) {
1683
+ return typeof value === "string" && ["free", "pro", "pro-plus", "business", "enterprise", "none"].includes(value);
1684
+ }
1587
1685
  function isValidTrack(value) {
1588
1686
  return typeof value === "string" && ["quick-flow", "bmad-method", "enterprise"].includes(value);
1589
1687
  }
1688
+ function isValidThinkingLevel(value) {
1689
+ return typeof value === "string" && ["off", "low", "medium", "high"].includes(value);
1690
+ }
1691
+ function isValidProvider(value) {
1692
+ return typeof value === "string" && ["anthropic", "openai", "google", "github-copilot"].includes(value);
1693
+ }
1694
+ function validateAgentSettings(settings) {
1695
+ if (typeof settings !== "object" || settings === null) {
1696
+ return void 0;
1697
+ }
1698
+ const result = {};
1699
+ const settingsObj = settings;
1700
+ const agentKeys = [
1701
+ "sisyphus",
1702
+ "oracle",
1703
+ "librarian",
1704
+ "frontend",
1705
+ "documentWriter",
1706
+ "multimodalLooker"
1707
+ ];
1708
+ for (const key of agentKeys) {
1709
+ if (key in settingsObj && typeof settingsObj[key] === "object" && settingsObj[key] !== null) {
1710
+ const agentSetting = settingsObj[key];
1711
+ const validated = {};
1712
+ if (typeof agentSetting.temperature === "number" && agentSetting.temperature >= 0 && agentSetting.temperature <= 2) {
1713
+ validated.temperature = agentSetting.temperature;
1714
+ }
1715
+ if (isValidThinkingLevel(agentSetting.thinkingLevel)) {
1716
+ validated.thinkingLevel = agentSetting.thinkingLevel;
1717
+ }
1718
+ if (Object.keys(validated).length > 0) {
1719
+ result[key] = validated;
1720
+ }
1721
+ }
1722
+ }
1723
+ if ("overrides" in settingsObj && typeof settingsObj.overrides === "object" && settingsObj.overrides !== null) {
1724
+ const overrides = settingsObj.overrides;
1725
+ result.overrides = {};
1726
+ for (const [modelId, modelSettings] of Object.entries(overrides)) {
1727
+ if (typeof modelSettings === "object" && modelSettings !== null) {
1728
+ const ms = modelSettings;
1729
+ const validated = {};
1730
+ if (typeof ms.temperature === "number" && ms.temperature >= 0 && ms.temperature <= 2) {
1731
+ validated.temperature = ms.temperature;
1732
+ }
1733
+ if (isValidThinkingLevel(ms.thinkingLevel)) {
1734
+ validated.thinkingLevel = ms.thinkingLevel;
1735
+ }
1736
+ if (Object.keys(validated).length > 0) {
1737
+ result.overrides[modelId] = validated;
1738
+ }
1739
+ }
1740
+ }
1741
+ }
1742
+ return Object.keys(result).length > 0 ? result : void 0;
1743
+ }
1744
+ function validateModelSettings(settings) {
1745
+ return validateAgentSettings(settings);
1746
+ }
1747
+ function validateCustomModels(models) {
1748
+ const validated = [];
1749
+ for (const model of models) {
1750
+ if (typeof model !== "object" || model === null) continue;
1751
+ const m = model;
1752
+ if (typeof m.id !== "string" || typeof m.name !== "string" || !isValidProvider(m.provider)) {
1753
+ continue;
1754
+ }
1755
+ const customModel = {
1756
+ id: m.id,
1757
+ name: m.name,
1758
+ provider: m.provider
1759
+ };
1760
+ if (typeof m.description === "string") {
1761
+ customModel.description = m.description;
1762
+ }
1763
+ if (typeof m.capabilities === "object" && m.capabilities !== null) {
1764
+ const caps = m.capabilities;
1765
+ customModel.capabilities = {};
1766
+ if (typeof caps.thinking === "boolean") {
1767
+ customModel.capabilities.thinking = caps.thinking;
1768
+ }
1769
+ if (typeof caps.contextWindow === "number") {
1770
+ customModel.capabilities.contextWindow = caps.contextWindow;
1771
+ }
1772
+ if (typeof caps.supportsTemperature === "boolean") {
1773
+ customModel.capabilities.supportsTemperature = caps.supportsTemperature;
1774
+ }
1775
+ }
1776
+ validated.push(customModel);
1777
+ }
1778
+ return validated.length > 0 ? validated : void 0;
1779
+ }
1590
1780
  function validateConfig(config) {
1591
1781
  const result = AthenaConfigSchema.safeParse(config);
1592
1782
  if (!result.success) {
@@ -1604,7 +1794,8 @@ function getDefaultConfig() {
1604
1794
  subscriptions: {
1605
1795
  claude: { enabled: false, tier: "none" },
1606
1796
  openai: { enabled: false },
1607
- google: { enabled: false, authMethod: "none" }
1797
+ google: { enabled: false, authMethod: "none" },
1798
+ githubCopilot: { enabled: false, plan: "none" }
1608
1799
  },
1609
1800
  models: {
1610
1801
  sisyphus: "anthropic/claude-sonnet-4",
@@ -1644,6 +1835,12 @@ function mergeConfigs(...configs) {
1644
1835
  ...config.subscriptions.google
1645
1836
  };
1646
1837
  }
1838
+ if (config.subscriptions.githubCopilot) {
1839
+ result.subscriptions.githubCopilot = {
1840
+ ...result.subscriptions.githubCopilot,
1841
+ ...config.subscriptions.githubCopilot
1842
+ };
1843
+ }
1647
1844
  }
1648
1845
  if (config.models) {
1649
1846
  result.models = { ...result.models, ...config.models };
@@ -1669,7 +1866,7 @@ var OpenCodeAthena = async (ctx) => {
1669
1866
  await tracker.initialize();
1670
1867
  const tools = createTools(ctx, tracker, config);
1671
1868
  const sessionHooks = createSessionHooks(ctx, tracker, config);
1672
- const toolHooks = createToolHooks();
1869
+ const toolHooks = createToolHooks(tracker, config);
1673
1870
  const compactionHook = createCompactionHook(tracker);
1674
1871
  return {
1675
1872
  // Custom tools for BMAD integration