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.
package/dist/index.js CHANGED
@@ -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
  }
@@ -152,7 +199,8 @@ var DEFAULTS = {
152
199
  notifications: true,
153
200
  contextMonitor: true,
154
201
  commentChecker: true,
155
- lspTools: true
202
+ lspTools: true,
203
+ autoGitOperations: false
156
204
  },
157
205
  /** Default MCPs enabled */
158
206
  mcps: {
@@ -1379,6 +1427,11 @@ var SubscriptionSchema = z.object({
1379
1427
  google: z.object({
1380
1428
  enabled: z.boolean(),
1381
1429
  authMethod: z.enum(["antigravity", "personal", "api", "none"])
1430
+ }),
1431
+ githubCopilot: z.object({
1432
+ enabled: z.boolean(),
1433
+ plan: z.enum(["free", "pro", "pro-plus", "business", "enterprise", "none"]),
1434
+ enabledModels: z.array(z.string()).optional()
1382
1435
  })
1383
1436
  });
1384
1437
  var BmadConfigSchema = z.object({
@@ -1393,20 +1446,47 @@ var FeaturesSchema = z.object({
1393
1446
  notifications: z.boolean(),
1394
1447
  contextMonitor: z.boolean(),
1395
1448
  commentChecker: z.boolean(),
1396
- lspTools: z.boolean()
1449
+ lspTools: z.boolean(),
1450
+ autoGitOperations: z.boolean().default(false)
1397
1451
  });
1398
1452
  var McpsSchema = z.object({
1399
1453
  context7: z.boolean(),
1400
1454
  exa: z.boolean(),
1401
1455
  grepApp: z.boolean()
1402
1456
  });
1457
+ var ThinkingLevelSchema = z.enum(["off", "low", "medium", "high"]);
1458
+ var AgentSettingsSchema = z.object({
1459
+ temperature: z.number().min(0).max(1).optional(),
1460
+ thinkingLevel: ThinkingLevelSchema.optional()
1461
+ });
1462
+ var CustomModelDefinitionSchema = z.object({
1463
+ id: z.string(),
1464
+ name: z.string(),
1465
+ provider: z.enum(["anthropic", "openai", "google", "github-copilot"]),
1466
+ description: z.string().optional(),
1467
+ capabilities: z.object({
1468
+ thinking: z.boolean().optional(),
1469
+ contextWindow: z.number().optional(),
1470
+ supportsTemperature: z.boolean().optional()
1471
+ }).optional()
1472
+ });
1403
1473
  var ModelsSchema = z.object({
1404
1474
  sisyphus: z.string().describe("Model for main orchestrator agent"),
1405
1475
  oracle: z.string().describe("Model for debugging/reasoning agent"),
1406
1476
  librarian: z.string().describe("Model for research/documentation agent"),
1407
1477
  frontend: z.string().optional().describe("Model for UI/UX agent"),
1408
1478
  documentWriter: z.string().optional().describe("Model for documentation generation agent"),
1409
- multimodalLooker: z.string().optional().describe("Model for image analysis agent")
1479
+ multimodalLooker: z.string().optional().describe("Model for image analysis agent"),
1480
+ settings: z.object({
1481
+ sisyphus: AgentSettingsSchema.optional(),
1482
+ oracle: AgentSettingsSchema.optional(),
1483
+ librarian: AgentSettingsSchema.optional(),
1484
+ frontend: AgentSettingsSchema.optional(),
1485
+ documentWriter: AgentSettingsSchema.optional(),
1486
+ multimodalLooker: AgentSettingsSchema.optional(),
1487
+ overrides: z.record(z.string(), AgentSettingsSchema).optional()
1488
+ }).optional(),
1489
+ custom: z.array(CustomModelDefinitionSchema).optional()
1410
1490
  });
1411
1491
  var AthenaConfigSchema = z.object({
1412
1492
  $schema: z.string().optional(),
@@ -1538,22 +1618,37 @@ function validatePartialConfig(config, filePath) {
1538
1618
  authMethod: isValidAuthMethod(google.authMethod) ? google.authMethod : "none"
1539
1619
  };
1540
1620
  }
1621
+ if (subs.githubCopilot && typeof subs.githubCopilot === "object") {
1622
+ const copilot = subs.githubCopilot;
1623
+ result.subscriptions.githubCopilot = {
1624
+ enabled: typeof copilot.enabled === "boolean" ? copilot.enabled : false,
1625
+ plan: isValidCopilotPlan(copilot.plan) ? copilot.plan : "none",
1626
+ enabledModels: Array.isArray(copilot.enabledModels) ? copilot.enabledModels.filter((m) => typeof m === "string") : void 0
1627
+ };
1628
+ }
1541
1629
  }
1542
1630
  if ("models" in configObj && typeof configObj.models === "object") {
1543
1631
  const models = configObj.models;
1544
1632
  result.models = {};
1545
- for (const key of [
1633
+ const modelKeys = [
1546
1634
  "sisyphus",
1547
1635
  "oracle",
1548
1636
  "librarian",
1549
1637
  "frontend",
1550
1638
  "documentWriter",
1551
1639
  "multimodalLooker"
1552
- ]) {
1640
+ ];
1641
+ for (const key of modelKeys) {
1553
1642
  if (key in models && typeof models[key] === "string") {
1554
1643
  result.models[key] = models[key];
1555
1644
  }
1556
1645
  }
1646
+ if ("settings" in models && typeof models.settings === "object" && models.settings !== null) {
1647
+ result.models.settings = validateModelSettings(models.settings);
1648
+ }
1649
+ if ("custom" in models && Array.isArray(models.custom)) {
1650
+ result.models.custom = validateCustomModels(models.custom);
1651
+ }
1557
1652
  }
1558
1653
  if ("bmad" in configObj && typeof configObj.bmad === "object") {
1559
1654
  const bmad = configObj.bmad;
@@ -1602,9 +1697,104 @@ function isValidTier(value) {
1602
1697
  function isValidAuthMethod(value) {
1603
1698
  return typeof value === "string" && ["antigravity", "personal", "api", "none"].includes(value);
1604
1699
  }
1700
+ function isValidCopilotPlan(value) {
1701
+ return typeof value === "string" && ["free", "pro", "pro-plus", "business", "enterprise", "none"].includes(value);
1702
+ }
1605
1703
  function isValidTrack(value) {
1606
1704
  return typeof value === "string" && ["quick-flow", "bmad-method", "enterprise"].includes(value);
1607
1705
  }
1706
+ function isValidThinkingLevel(value) {
1707
+ return typeof value === "string" && ["off", "low", "medium", "high"].includes(value);
1708
+ }
1709
+ function isValidProvider(value) {
1710
+ return typeof value === "string" && ["anthropic", "openai", "google", "github-copilot"].includes(value);
1711
+ }
1712
+ function validateAgentSettings(settings) {
1713
+ if (typeof settings !== "object" || settings === null) {
1714
+ return void 0;
1715
+ }
1716
+ const result = {};
1717
+ const settingsObj = settings;
1718
+ const agentKeys = [
1719
+ "sisyphus",
1720
+ "oracle",
1721
+ "librarian",
1722
+ "frontend",
1723
+ "documentWriter",
1724
+ "multimodalLooker"
1725
+ ];
1726
+ for (const key of agentKeys) {
1727
+ if (key in settingsObj && typeof settingsObj[key] === "object" && settingsObj[key] !== null) {
1728
+ const agentSetting = settingsObj[key];
1729
+ const validated = {};
1730
+ if (typeof agentSetting.temperature === "number" && agentSetting.temperature >= 0 && agentSetting.temperature <= 2) {
1731
+ validated.temperature = agentSetting.temperature;
1732
+ }
1733
+ if (isValidThinkingLevel(agentSetting.thinkingLevel)) {
1734
+ validated.thinkingLevel = agentSetting.thinkingLevel;
1735
+ }
1736
+ if (Object.keys(validated).length > 0) {
1737
+ result[key] = validated;
1738
+ }
1739
+ }
1740
+ }
1741
+ if ("overrides" in settingsObj && typeof settingsObj.overrides === "object" && settingsObj.overrides !== null) {
1742
+ const overrides = settingsObj.overrides;
1743
+ result.overrides = {};
1744
+ for (const [modelId, modelSettings] of Object.entries(overrides)) {
1745
+ if (typeof modelSettings === "object" && modelSettings !== null) {
1746
+ const ms = modelSettings;
1747
+ const validated = {};
1748
+ if (typeof ms.temperature === "number" && ms.temperature >= 0 && ms.temperature <= 2) {
1749
+ validated.temperature = ms.temperature;
1750
+ }
1751
+ if (isValidThinkingLevel(ms.thinkingLevel)) {
1752
+ validated.thinkingLevel = ms.thinkingLevel;
1753
+ }
1754
+ if (Object.keys(validated).length > 0) {
1755
+ result.overrides[modelId] = validated;
1756
+ }
1757
+ }
1758
+ }
1759
+ }
1760
+ return Object.keys(result).length > 0 ? result : void 0;
1761
+ }
1762
+ function validateModelSettings(settings) {
1763
+ return validateAgentSettings(settings);
1764
+ }
1765
+ function validateCustomModels(models) {
1766
+ const validated = [];
1767
+ for (const model of models) {
1768
+ if (typeof model !== "object" || model === null) continue;
1769
+ const m = model;
1770
+ if (typeof m.id !== "string" || typeof m.name !== "string" || !isValidProvider(m.provider)) {
1771
+ continue;
1772
+ }
1773
+ const customModel = {
1774
+ id: m.id,
1775
+ name: m.name,
1776
+ provider: m.provider
1777
+ };
1778
+ if (typeof m.description === "string") {
1779
+ customModel.description = m.description;
1780
+ }
1781
+ if (typeof m.capabilities === "object" && m.capabilities !== null) {
1782
+ const caps = m.capabilities;
1783
+ customModel.capabilities = {};
1784
+ if (typeof caps.thinking === "boolean") {
1785
+ customModel.capabilities.thinking = caps.thinking;
1786
+ }
1787
+ if (typeof caps.contextWindow === "number") {
1788
+ customModel.capabilities.contextWindow = caps.contextWindow;
1789
+ }
1790
+ if (typeof caps.supportsTemperature === "boolean") {
1791
+ customModel.capabilities.supportsTemperature = caps.supportsTemperature;
1792
+ }
1793
+ }
1794
+ validated.push(customModel);
1795
+ }
1796
+ return validated.length > 0 ? validated : void 0;
1797
+ }
1608
1798
  function validateConfig(config) {
1609
1799
  const result = AthenaConfigSchema.safeParse(config);
1610
1800
  if (!result.success) {
@@ -1622,7 +1812,8 @@ function getDefaultConfig() {
1622
1812
  subscriptions: {
1623
1813
  claude: { enabled: false, tier: "none" },
1624
1814
  openai: { enabled: false },
1625
- google: { enabled: false, authMethod: "none" }
1815
+ google: { enabled: false, authMethod: "none" },
1816
+ githubCopilot: { enabled: false, plan: "none" }
1626
1817
  },
1627
1818
  models: {
1628
1819
  sisyphus: "anthropic/claude-sonnet-4",
@@ -1662,6 +1853,12 @@ function mergeConfigs(...configs) {
1662
1853
  ...config.subscriptions.google
1663
1854
  };
1664
1855
  }
1856
+ if (config.subscriptions.githubCopilot) {
1857
+ result.subscriptions.githubCopilot = {
1858
+ ...result.subscriptions.githubCopilot,
1859
+ ...config.subscriptions.githubCopilot
1860
+ };
1861
+ }
1665
1862
  }
1666
1863
  if (config.models) {
1667
1864
  result.models = { ...result.models, ...config.models };
@@ -1687,7 +1884,7 @@ var OpenCodeAthena = async (ctx) => {
1687
1884
  await tracker.initialize();
1688
1885
  const tools = createTools(ctx, tracker, config);
1689
1886
  const sessionHooks = createSessionHooks(ctx, tracker, config);
1690
- const toolHooks = createToolHooks();
1887
+ const toolHooks = createToolHooks(tracker, config);
1691
1888
  const compactionHook = createCompactionHook(tracker);
1692
1889
  return {
1693
1890
  // Custom tools for BMAD integration