@iaforged/context-code 1.0.77 → 1.0.79

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 (121) hide show
  1. package/README.md +68 -68
  2. package/cli.js +8515 -8515
  3. package/context-bootstrap.js +27 -27
  4. package/dist/src/bootstrap/state.js +3 -0
  5. package/dist/src/bridge/bridgeMain.js +40 -40
  6. package/dist/src/cli/print.js +12 -12
  7. package/dist/src/commands/agent/agent.js +8 -0
  8. package/dist/src/commands/commit-push-pr.js +55 -55
  9. package/dist/src/commands/createMovedToPluginCommand.js +9 -9
  10. package/dist/src/commands/init-verifiers.js +238 -238
  11. package/dist/src/commands/init.js +216 -216
  12. package/dist/src/commands/install.js +2 -2
  13. package/dist/src/commands/login/login.js +24 -10
  14. package/dist/src/commands/orchestrate/index.js +1 -1
  15. package/dist/src/commands/orchestrate/orchestrate.js +110 -24
  16. package/dist/src/commands/profile/profile.js +15 -1
  17. package/dist/src/commands/provider/index.js +1 -1
  18. package/dist/src/commands/provider/provider.js +34 -1
  19. package/dist/src/commands/review.js +22 -22
  20. package/dist/src/commands/run/index.js +2 -2
  21. package/dist/src/commands/run/run.js +63 -61
  22. package/dist/src/commands/team/index.js +1 -1
  23. package/dist/src/commands/team/team.js +84 -76
  24. package/dist/src/commands/team-auto/teamAuto.js +89 -29
  25. package/dist/src/commands/terminalSetup/terminalSetup.js +24 -24
  26. package/dist/src/commands/usage/index.js +7 -0
  27. package/dist/src/commands/usage/usage.js +5 -0
  28. package/dist/src/commands/workspace/workspace.js +39 -31
  29. package/dist/src/commands.js +0 -2
  30. package/dist/src/components/ConsoleOAuthFlow.js +92 -14
  31. package/dist/src/components/ModelPicker.js +2 -0
  32. package/dist/src/components/agents/generateAgent.js +92 -92
  33. package/dist/src/components/grove/Grove.js +10 -10
  34. package/dist/src/components/permissions/AskUserQuestionPermissionRequest/AskUserQuestionPermissionRequest.js +8 -8
  35. package/dist/src/constants/geminiOAuth.js +13 -0
  36. package/dist/src/constants/github-app.js +134 -134
  37. package/dist/src/constants/prompts.js +123 -123
  38. package/dist/src/coordinator/coordinatorMode.js +252 -252
  39. package/dist/src/hooks/useTypeahead.js +7 -7
  40. package/dist/src/ink/reconciler.js +7 -7
  41. package/dist/src/main.js +5 -5
  42. package/dist/src/memdir/findRelevantMemories.js +6 -6
  43. package/dist/src/services/MagicDocs/prompts.js +56 -56
  44. package/dist/src/services/PromptSuggestion/promptSuggestion.js +29 -29
  45. package/dist/src/services/SessionMemory/prompts.js +66 -66
  46. package/dist/src/services/api/openai.js +584 -21
  47. package/dist/src/services/limits/adapters/ollama.js +3 -3
  48. package/dist/src/services/oauth/geminiCli.js +107 -0
  49. package/dist/src/services/orchestration/execution/AgentTaskExecutor.js +5 -3
  50. package/dist/src/services/orchestration/execution/OrchestrationExecutionRuntime.js +18 -18
  51. package/dist/src/services/orchestration/global/reporting.js +2 -2
  52. package/dist/src/services/toolUseSummary/toolUseSummaryGenerator.js +9 -9
  53. package/dist/src/skills/bundled/batch.js +78 -78
  54. package/dist/src/skills/bundled/claudeApi.js +34 -34
  55. package/dist/src/skills/bundled/claudeInChrome.js +4 -4
  56. package/dist/src/skills/bundled/debug.js +36 -36
  57. package/dist/src/skills/bundled/scheduleRemoteAgents.js +151 -151
  58. package/dist/src/skills/bundled/skillify.js +132 -132
  59. package/dist/src/skills/bundled/stuck.js +53 -53
  60. package/dist/src/skills/bundled/updateConfig.js +418 -418
  61. package/dist/src/tasks/RemoteAgentTask/RemoteAgentTask.js +26 -26
  62. package/dist/src/tools/AgentTool/AgentTool.js +7 -7
  63. package/dist/src/tools/AgentTool/built-in/claudeCodeGuideAgent.js +67 -67
  64. package/dist/src/tools/AgentTool/built-in/exploreAgent.js +32 -32
  65. package/dist/src/tools/AgentTool/built-in/generalPurposeAgent.js +13 -13
  66. package/dist/src/tools/AgentTool/built-in/planAgent.js +49 -49
  67. package/dist/src/tools/AgentTool/built-in/statuslineSetup.js +129 -129
  68. package/dist/src/tools/AgentTool/built-in/verificationAgent.js +119 -119
  69. package/dist/src/tools/AgentTool/prompt.js +131 -131
  70. package/dist/src/tools/AgentTool/runAgent.js +9 -9
  71. package/dist/src/tools/BashTool/BashTool.js +10 -10
  72. package/dist/src/tools/BashTool/prompt.js +94 -94
  73. package/dist/src/tools/ConfigTool/prompt.js +29 -29
  74. package/dist/src/tools/EnterWorktreeTool/prompt.js +27 -27
  75. package/dist/src/tools/FileReadTool/prompt.js +12 -12
  76. package/dist/src/tools/PowerShellTool/prompt.js +82 -82
  77. package/dist/src/tools/RemoteTriggerTool/prompt.js +9 -9
  78. package/dist/src/tools/ScheduleCronTool/prompt.js +37 -37
  79. package/dist/src/tools/TeamCreateTool/prompt.js +110 -110
  80. package/dist/src/tools/TeamDeleteTool/prompt.js +13 -13
  81. package/dist/src/utils/advisor.js +15 -15
  82. package/dist/src/utils/api.js +2 -2
  83. package/dist/src/utils/auth.js +207 -2
  84. package/dist/src/utils/autoUpdater.js +18 -18
  85. package/dist/src/utils/bash/ShellSnapshot.js +86 -86
  86. package/dist/src/utils/bash/commands.js +61 -61
  87. package/dist/src/utils/claudeInChrome/prompt.js +53 -53
  88. package/dist/src/utils/claudeInChrome/setup.js +8 -8
  89. package/dist/src/utils/databaseMcp/server/queries.js +632 -632
  90. package/dist/src/utils/deepLink/registerProtocol.js +35 -35
  91. package/dist/src/utils/deepLink/terminalLauncher.js +12 -12
  92. package/dist/src/utils/hooks/execAgentHook.js +7 -7
  93. package/dist/src/utils/hooks/execPromptHook.js +4 -4
  94. package/dist/src/utils/hooks/skillImprovement.js +36 -36
  95. package/dist/src/utils/logoV2Utils.js +1 -1
  96. package/dist/src/utils/mcp/dateTimeParser.js +9 -9
  97. package/dist/src/utils/messages.js +191 -191
  98. package/dist/src/utils/model/model.js +18 -0
  99. package/dist/src/utils/model/modelOptions.js +51 -1
  100. package/dist/src/utils/model/modelStrings.js +5 -1
  101. package/dist/src/utils/model/modelSupportOverrides.js +3 -0
  102. package/dist/src/utils/model/providerBaseUrls.js +6 -1
  103. package/dist/src/utils/model/providerCatalog.js +64 -28
  104. package/dist/src/utils/model/providerModels.js +88 -17
  105. package/dist/src/utils/model/providerProfiles.js +8 -0
  106. package/dist/src/utils/model/providerProfilesDb.js +578 -393
  107. package/dist/src/utils/model/providerSwitch.js +12 -0
  108. package/dist/src/utils/model/providerWorkspaces.js +2 -0
  109. package/dist/src/utils/model/providers.js +65 -2
  110. package/dist/src/utils/orchestration/store/providerWorkspaceStore.js +3 -1
  111. package/dist/src/utils/orchestration/store/runStore.js +47 -47
  112. package/dist/src/utils/orchestration/store/teamStore.js +61 -61
  113. package/dist/src/utils/powershell/parser.js +253 -253
  114. package/dist/src/utils/sessionTitle.js +12 -12
  115. package/dist/src/utils/sideQuestion.js +17 -17
  116. package/dist/src/utils/status.js +1 -1
  117. package/dist/src/utils/swarm/backends/registry.js +9 -9
  118. package/dist/src/utils/telemetry/instrumentation.js +9 -9
  119. package/dist/src/utils/teleport.js +15 -15
  120. package/dist/src/utils/undercover.js +28 -28
  121. package/package.json +1 -1
@@ -1,113 +1,113 @@
1
1
  export function getPrompt() {
2
- return `
3
- # TeamCreate
4
-
5
- ## When to Use
6
-
7
- Use this tool proactively whenever:
8
- - The user explicitly asks to use a team, swarm, or group of agents
9
- - The user mentions wanting agents to work together, coordinate, or collaborate
10
- - A task is complex enough that it would benefit from parallel work by multiple agents (e.g., building a full-stack feature with frontend and backend work, refactoring a codebase while keeping tests passing, implementing a multi-step project with research, planning, and coding phases)
11
-
12
- When in doubt about whether a task warrants a team, prefer spawning a team.
13
-
14
- ## Choosing Agent Types for Teammates
15
-
16
- When spawning teammates via the Agent tool, choose the \`subagent_type\` based on what tools the agent needs for its task. Each agent type has a different set of available tools — match the agent to the work:
17
-
18
- - **Read-only agents** (e.g., Explore, Plan) cannot edit or write files. Only assign them research, search, or planning tasks. Never assign them implementation work.
19
- - **Full-capability agents** (e.g., general-purpose) have access to all tools including file editing, writing, and bash. Use these for tasks that require making changes.
20
- - **Custom agents** defined in \`.claude/agents/\` may have their own tool restrictions. Check their descriptions to understand what they can and cannot do.
21
-
22
- Always review the agent type descriptions and their available tools listed in the Agent tool prompt before selecting a \`subagent_type\` for a teammate.
23
-
24
- Create a new team to coordinate multiple agents working on a project. Teams have a 1:1 correspondence with task lists (Team = TaskList).
25
-
26
- \`\`\`
27
- {
28
- "team_name": "my-project",
29
- "description": "Working on feature X"
30
- }
31
- \`\`\`
32
-
33
- This creates:
34
- - A team file at \`~/.context/teams/{team-name}/config.json\`
35
- - A corresponding task list directory at \`~/.context/tasks/{team-name}/\`
36
-
37
- ## Team Workflow
38
-
39
- 1. **Create a team** with TeamCreate - this creates both the team and its task list
40
- 2. **Create tasks** using the Task tools (TaskCreate, TaskList, etc.) - they automatically use the team's task list
41
- 3. **Spawn teammates** using the Agent tool with \`team_name\` and \`name\` parameters to create teammates that join the team
42
- 4. **Assign tasks** using TaskUpdate with \`owner\` to give tasks to idle teammates
43
- 5. **Teammates work on assigned tasks** and mark them completed via TaskUpdate
44
- 6. **Teammates go idle between turns** - after each turn, teammates automatically go idle and send a notification. IMPORTANT: Be patient with idle teammates! Don't comment on their idleness until it actually impacts your work.
45
- 7. **Shutdown your team** - when the task is completed, gracefully shut down your teammates via SendMessage with \`message: {type: "shutdown_request"}\`.
46
-
47
- ## Task Ownership
48
-
49
- Tasks are assigned using TaskUpdate with the \`owner\` parameter. Any agent can set or change task ownership via TaskUpdate.
50
-
51
- ## Automatic Message Delivery
52
-
53
- **IMPORTANT**: Messages from teammates are automatically delivered to you. You do NOT need to manually check your inbox.
54
-
55
- When you spawn teammates:
56
- - They will send you messages when they complete tasks or need help
57
- - These messages appear automatically as new conversation turns (like user messages)
58
- - If you're busy (mid-turn), messages are queued and delivered when your turn ends
59
- - The UI shows a brief notification with the sender's name when messages are waiting
60
-
61
- Messages will be delivered automatically.
62
-
63
- When reporting on teammate messages, you do NOT need to quote the original message—it's already rendered to the user.
64
-
65
- ## Teammate Idle State
66
-
67
- Teammates go idle after every turn—this is completely normal and expected. A teammate going idle immediately after sending you a message does NOT mean they are done or unavailable. Idle simply means they are waiting for input.
68
-
69
- - **Idle teammates can receive messages.** Sending a message to an idle teammate wakes them up and they will process it normally.
70
- - **Idle notifications are automatic.** The system sends an idle notification whenever a teammate's turn ends. You do not need to react to idle notifications unless you want to assign new work or send a follow-up message.
71
- - **Do not treat idle as an error.** A teammate sending a message and then going idle is the normal flow—they sent their message and are now waiting for a response.
72
- - **Peer DM visibility.** When a teammate sends a DM to another teammate, a brief summary is included in their idle notification. This gives you visibility into peer collaboration without the full message content. You do not need to respond to these summaries — they are informational.
73
-
74
- ## Discovering Team Members
75
-
76
- Teammates can read the team config file to discover other team members:
77
- - **Team config location**: \`~/.context/teams/{team-name}/config.json\`
78
-
79
- The config file contains a \`members\` array with each teammate's:
80
- - \`name\`: Human-readable name (**always use this** for messaging and task assignment)
81
- - \`agentId\`: Unique identifier (for reference only - do not use for communication)
82
- - \`agentType\`: Role/type of the agent
83
-
84
- **IMPORTANT**: Always refer to teammates by their NAME (e.g., "team-lead", "researcher", "tester"). Names are used for:
85
- - \`to\` when sending messages
86
- - Identifying task owners
87
-
88
- Example of reading team config:
89
- \`\`\`
90
- Use the Read tool to read ~/.context/teams/{team-name}/config.json
91
- \`\`\`
92
-
93
- ## Task List Coordination
94
-
95
- Teams share a task list that all teammates can access at \`~/.context/tasks/{team-name}/\`.
96
-
97
- Teammates should:
98
- 1. Check TaskList periodically, **especially after completing each task**, to find available work or see newly unblocked tasks
99
- 2. Claim unassigned, unblocked tasks with TaskUpdate (set \`owner\` to your name). **Prefer tasks in ID order** (lowest ID first) when multiple tasks are available, as earlier tasks often set up context for later ones
100
- 3. Create new tasks with \`TaskCreate\` when identifying additional work
101
- 4. Mark tasks as completed with \`TaskUpdate\` when done, then check TaskList for next work
102
- 5. Coordinate with other teammates by reading the task list status
103
- 6. If all available tasks are blocked, notify the team lead or help resolve blocking tasks
104
-
105
- **IMPORTANT notes for communication with your team**:
106
- - Do not use terminal tools to view your team's activity; always send a message to your teammates (and remember, refer to them by name).
107
- - Your team cannot hear you if you do not use the SendMessage tool. Always send a message to your teammates if you are responding to them.
108
- - Do NOT send structured JSON status messages like \`{"type":"idle",...}\` or \`{"type":"task_completed",...}\`. Just communicate in plain text when you need to message teammates.
109
- - Use TaskUpdate to mark tasks completed.
110
- - If you are an agent in the team, the system will automatically send idle notifications to the team lead when you stop.
111
-
2
+ return `
3
+ # TeamCreate
4
+
5
+ ## When to Use
6
+
7
+ Use this tool proactively whenever:
8
+ - The user explicitly asks to use a team, swarm, or group of agents
9
+ - The user mentions wanting agents to work together, coordinate, or collaborate
10
+ - A task is complex enough that it would benefit from parallel work by multiple agents (e.g., building a full-stack feature with frontend and backend work, refactoring a codebase while keeping tests passing, implementing a multi-step project with research, planning, and coding phases)
11
+
12
+ When in doubt about whether a task warrants a team, prefer spawning a team.
13
+
14
+ ## Choosing Agent Types for Teammates
15
+
16
+ When spawning teammates via the Agent tool, choose the \`subagent_type\` based on what tools the agent needs for its task. Each agent type has a different set of available tools — match the agent to the work:
17
+
18
+ - **Read-only agents** (e.g., Explore, Plan) cannot edit or write files. Only assign them research, search, or planning tasks. Never assign them implementation work.
19
+ - **Full-capability agents** (e.g., general-purpose) have access to all tools including file editing, writing, and bash. Use these for tasks that require making changes.
20
+ - **Custom agents** defined in \`.claude/agents/\` may have their own tool restrictions. Check their descriptions to understand what they can and cannot do.
21
+
22
+ Always review the agent type descriptions and their available tools listed in the Agent tool prompt before selecting a \`subagent_type\` for a teammate.
23
+
24
+ Create a new team to coordinate multiple agents working on a project. Teams have a 1:1 correspondence with task lists (Team = TaskList).
25
+
26
+ \`\`\`
27
+ {
28
+ "team_name": "my-project",
29
+ "description": "Working on feature X"
30
+ }
31
+ \`\`\`
32
+
33
+ This creates:
34
+ - A team file at \`~/.context/teams/{team-name}/config.json\`
35
+ - A corresponding task list directory at \`~/.context/tasks/{team-name}/\`
36
+
37
+ ## Team Workflow
38
+
39
+ 1. **Create a team** with TeamCreate - this creates both the team and its task list
40
+ 2. **Create tasks** using the Task tools (TaskCreate, TaskList, etc.) - they automatically use the team's task list
41
+ 3. **Spawn teammates** using the Agent tool with \`team_name\` and \`name\` parameters to create teammates that join the team
42
+ 4. **Assign tasks** using TaskUpdate with \`owner\` to give tasks to idle teammates
43
+ 5. **Teammates work on assigned tasks** and mark them completed via TaskUpdate
44
+ 6. **Teammates go idle between turns** - after each turn, teammates automatically go idle and send a notification. IMPORTANT: Be patient with idle teammates! Don't comment on their idleness until it actually impacts your work.
45
+ 7. **Shutdown your team** - when the task is completed, gracefully shut down your teammates via SendMessage with \`message: {type: "shutdown_request"}\`.
46
+
47
+ ## Task Ownership
48
+
49
+ Tasks are assigned using TaskUpdate with the \`owner\` parameter. Any agent can set or change task ownership via TaskUpdate.
50
+
51
+ ## Automatic Message Delivery
52
+
53
+ **IMPORTANT**: Messages from teammates are automatically delivered to you. You do NOT need to manually check your inbox.
54
+
55
+ When you spawn teammates:
56
+ - They will send you messages when they complete tasks or need help
57
+ - These messages appear automatically as new conversation turns (like user messages)
58
+ - If you're busy (mid-turn), messages are queued and delivered when your turn ends
59
+ - The UI shows a brief notification with the sender's name when messages are waiting
60
+
61
+ Messages will be delivered automatically.
62
+
63
+ When reporting on teammate messages, you do NOT need to quote the original message—it's already rendered to the user.
64
+
65
+ ## Teammate Idle State
66
+
67
+ Teammates go idle after every turn—this is completely normal and expected. A teammate going idle immediately after sending you a message does NOT mean they are done or unavailable. Idle simply means they are waiting for input.
68
+
69
+ - **Idle teammates can receive messages.** Sending a message to an idle teammate wakes them up and they will process it normally.
70
+ - **Idle notifications are automatic.** The system sends an idle notification whenever a teammate's turn ends. You do not need to react to idle notifications unless you want to assign new work or send a follow-up message.
71
+ - **Do not treat idle as an error.** A teammate sending a message and then going idle is the normal flow—they sent their message and are now waiting for a response.
72
+ - **Peer DM visibility.** When a teammate sends a DM to another teammate, a brief summary is included in their idle notification. This gives you visibility into peer collaboration without the full message content. You do not need to respond to these summaries — they are informational.
73
+
74
+ ## Discovering Team Members
75
+
76
+ Teammates can read the team config file to discover other team members:
77
+ - **Team config location**: \`~/.context/teams/{team-name}/config.json\`
78
+
79
+ The config file contains a \`members\` array with each teammate's:
80
+ - \`name\`: Human-readable name (**always use this** for messaging and task assignment)
81
+ - \`agentId\`: Unique identifier (for reference only - do not use for communication)
82
+ - \`agentType\`: Role/type of the agent
83
+
84
+ **IMPORTANT**: Always refer to teammates by their NAME (e.g., "team-lead", "researcher", "tester"). Names are used for:
85
+ - \`to\` when sending messages
86
+ - Identifying task owners
87
+
88
+ Example of reading team config:
89
+ \`\`\`
90
+ Use the Read tool to read ~/.context/teams/{team-name}/config.json
91
+ \`\`\`
92
+
93
+ ## Task List Coordination
94
+
95
+ Teams share a task list that all teammates can access at \`~/.context/tasks/{team-name}/\`.
96
+
97
+ Teammates should:
98
+ 1. Check TaskList periodically, **especially after completing each task**, to find available work or see newly unblocked tasks
99
+ 2. Claim unassigned, unblocked tasks with TaskUpdate (set \`owner\` to your name). **Prefer tasks in ID order** (lowest ID first) when multiple tasks are available, as earlier tasks often set up context for later ones
100
+ 3. Create new tasks with \`TaskCreate\` when identifying additional work
101
+ 4. Mark tasks as completed with \`TaskUpdate\` when done, then check TaskList for next work
102
+ 5. Coordinate with other teammates by reading the task list status
103
+ 6. If all available tasks are blocked, notify the team lead or help resolve blocking tasks
104
+
105
+ **IMPORTANT notes for communication with your team**:
106
+ - Do not use terminal tools to view your team's activity; always send a message to your teammates (and remember, refer to them by name).
107
+ - Your team cannot hear you if you do not use the SendMessage tool. Always send a message to your teammates if you are responding to them.
108
+ - Do NOT send structured JSON status messages like \`{"type":"idle",...}\` or \`{"type":"task_completed",...}\`. Just communicate in plain text when you need to message teammates.
109
+ - Use TaskUpdate to mark tasks completed.
110
+ - If you are an agent in the team, the system will automatically send idle notifications to the team lead when you stop.
111
+
112
112
  `.trim();
113
113
  }
@@ -1,16 +1,16 @@
1
1
  export function getPrompt() {
2
- return `
3
- # TeamDelete
4
-
5
- Remove team and task directories when the swarm work is complete.
6
-
7
- This operation:
8
- - Removes the team directory (\`~/.context/teams/{team-name}/\`)
9
- - Removes the task directory (\`~/.context/tasks/{team-name}/\`)
10
- - Clears team context from the current session
11
-
12
- **IMPORTANT**: TeamDelete will fail if the team still has active members. Gracefully terminate teammates first, then call TeamDelete after all teammates have shut down.
13
-
14
- Use this when all teammates have finished their work and you want to clean up the team resources. The team name is automatically determined from the current session's team context.
2
+ return `
3
+ # TeamDelete
4
+
5
+ Remove team and task directories when the swarm work is complete.
6
+
7
+ This operation:
8
+ - Removes the team directory (\`~/.context/teams/{team-name}/\`)
9
+ - Removes the task directory (\`~/.context/tasks/{team-name}/\`)
10
+ - Clears team context from the current session
11
+
12
+ **IMPORTANT**: TeamDelete will fail if the team still has active members. Gracefully terminate teammates first, then call TeamDelete after all teammates have shut down.
13
+
14
+ Use this when all teammates have finished their work and you want to clean up the team resources. The team name is automatically determined from the current session's team context.
15
15
  `.trim();
16
16
  }
@@ -59,19 +59,19 @@ export function getAdvisorUsage(usage) {
59
59
  }
60
60
  return iterations.filter(it => it.type === 'advisor_message');
61
61
  }
62
- export const ADVISOR_TOOL_INSTRUCTIONS = `# Advisor Tool
63
-
64
- You have access to an \`advisor\` tool backed by a stronger reviewer model. It takes NO parameters -- when you call it, your entire conversation history is automatically forwarded. The advisor sees the task, every tool call you've made, every result you've seen.
65
-
66
- Call advisor BEFORE substantive work -- before writing code, before committing to an interpretation, before building on an assumption. If the task requires orientation first (finding files, reading code, seeing what's there), do that, then call advisor. Orientation is not substantive work. Writing, editing, and declaring an answer are.
67
-
68
- Also call advisor:
69
- - When you believe the task is complete. BEFORE this call, make your deliverable durable: write the file, stage the change, save the result. The advisor call takes time; if the session ends during it, a durable result persists and an unwritten one doesn't.
70
- - When stuck -- errors recurring, approach not converging, results that don't fit.
71
- - When considering a change of approach.
72
-
73
- On tasks longer than a few steps, call advisor at least once before committing to an approach and once before declaring done. On short reactive tasks where the next action is dictated by tool output you just read, you don't need to keep calling -- the advisor adds most of its value on the first call, before the approach crystallizes.
74
-
75
- Give the advice serious weight. If you follow a step and it fails empirically, or you have primary-source evidence that contradicts a specific claim (the file says X, the code does Y), adapt. A passing self-test is not evidence the advice is wrong -- it's evidence your test doesn't check what the advice is checking.
76
-
62
+ export const ADVISOR_TOOL_INSTRUCTIONS = `# Advisor Tool
63
+
64
+ You have access to an \`advisor\` tool backed by a stronger reviewer model. It takes NO parameters -- when you call it, your entire conversation history is automatically forwarded. The advisor sees the task, every tool call you've made, every result you've seen.
65
+
66
+ Call advisor BEFORE substantive work -- before writing code, before committing to an interpretation, before building on an assumption. If the task requires orientation first (finding files, reading code, seeing what's there), do that, then call advisor. Orientation is not substantive work. Writing, editing, and declaring an answer are.
67
+
68
+ Also call advisor:
69
+ - When you believe the task is complete. BEFORE this call, make your deliverable durable: write the file, stage the change, save the result. The advisor call takes time; if the session ends during it, a durable result persists and an unwritten one doesn't.
70
+ - When stuck -- errors recurring, approach not converging, results that don't fit.
71
+ - When considering a change of approach.
72
+
73
+ On tasks longer than a few steps, call advisor at least once before committing to an approach and once before declaring done. On short reactive tasks where the next action is dictated by tool output you just read, you don't need to keep calling -- the advisor adds most of its value on the first call, before the approach crystallizes.
74
+
75
+ Give the advice serious weight. If you follow a step and it fails empirically, or you have primary-source evidence that contradicts a specific claim (the file says X, the code does Y), adapt. A passing self-test is not evidence the advice is wrong -- it's evidence your test doesn't check what the advice is checking.
76
+
77
77
  If you've already retrieved data pointing one way and the advisor points another: don't silently switch. Surface the conflict in one more advisor call -- "I found X, you suggest Y, which constraint breaks the tie?" The advisor saw your evidence but may have underweighted it; a reconcile call is cheaper than committing to the wrong branch.`;
@@ -348,8 +348,8 @@ export function prependUserContext(messages, context) {
348
348
  createUserMessage({
349
349
  content: `<system-reminder>\nAs you answer the user's questions, you can use the following context:\n${Object.entries(context)
350
350
  .map(([key, value]) => `# ${key}\n${value}`)
351
- .join('\n')}
352
-
351
+ .join('\n')}
352
+
353
353
  IMPORTANT: this context may or may not be relevant to your tasks. You should not respond to this context unless it is highly relevant to your task.\n</system-reminder>\n`,
354
354
  isMeta: true,
355
355
  }),
@@ -6,9 +6,10 @@ import { mkdir, stat } from 'fs/promises';
6
6
  import memoize from 'lodash-es/memoize.js';
7
7
  import { CLAUDE_AI_PROFILE_SCOPE } from '../constants/oauth.js';
8
8
  import { logEvent, } from '../services/analytics/index.js';
9
+ import { GEMINI_CLI_OAUTH_CLIENT_ID, GEMINI_CLI_OAUTH_CLIENT_SECRET, GEMINI_CLI_OAUTH_SCOPES, GEMINI_CLI_OAUTH_TOKEN_URL, } from '../constants/geminiOAuth.js';
9
10
  import { getModelStrings } from './model/modelStrings.js';
10
11
  import { getAPIProvider, isOpenAICompatibleProvider, } from './model/providers.js';
11
- import { getResolvedProviderProfileId, isDefaultProfileId, isProfiledProvider, resolveProviderProfile, } from './model/providerProfiles.js';
12
+ import { getResolvedProviderProfileId, ensureProviderProfile, isDefaultProfileId, isProfiledProvider, resolveProviderProfile, } from './model/providerProfiles.js';
12
13
  import { getIsNonInteractiveSession, preferThirdPartyAuthentication, } from '../bootstrap/state.js';
13
14
  import { getMockSubscriptionType, shouldUseMockSubscription, } from '../services/mockRateLimits.js';
14
15
  import { isOAuthTokenExpired, refreshOpenAIOAuthToken, refreshOAuthToken, shouldUseClaudeAIAuth, } from '../services/oauth/client.js';
@@ -165,6 +166,9 @@ export function getStoredProviderOAuthTokens(provider, profileId) {
165
166
  return null;
166
167
  }
167
168
  }
169
+ if (provider === 'gemini-google') {
170
+ return null;
171
+ }
168
172
  const legacy = storage?.[getProviderOauthStorageKey(provider)];
169
173
  return legacy?.accessToken ? legacy : null;
170
174
  }
@@ -752,6 +756,7 @@ export function isGcpAuthRefreshFromProjectSettings() {
752
756
  * credential source exists (no ADC file, no env var), google-auth-library falls
753
757
  * through to the GCE metadata server which hangs ~12s outside GCP. */
754
758
  const GCP_CREDENTIALS_CHECK_TIMEOUT_MS = 5_000;
759
+ const GEMINI_GOOGLE_AUTH_SCOPES = GEMINI_CLI_OAUTH_SCOPES;
755
760
  /**
756
761
  * Check if GCP credentials are currently valid by attempting to get an access token.
757
762
  * This uses the same authentication chain that the Vertex SDK uses.
@@ -1296,6 +1301,198 @@ export function getOpenRouterAccessToken() {
1296
1301
  getStoredProviderApiKey('openrouter', getResolvedProviderProfileId('openrouter')) ||
1297
1302
  null);
1298
1303
  }
1304
+ export async function checkGeminiGoogleCredentialsValid() {
1305
+ try {
1306
+ const headers = await getGeminiGoogleAuthHeaders();
1307
+ const projectId = process.env.GEMINI_GOOGLE_PROJECT_ID?.trim() || undefined;
1308
+ const probe = fetch('https://cloudcode-pa.googleapis.com/v1internal:loadCodeAssist', {
1309
+ method: 'POST',
1310
+ headers,
1311
+ body: JSON.stringify({
1312
+ cloudaicompanionProject: projectId,
1313
+ metadata: {
1314
+ ideType: 'IDE_UNSPECIFIED',
1315
+ platform: 'PLATFORM_UNSPECIFIED',
1316
+ pluginType: 'GEMINI',
1317
+ duetProject: projectId,
1318
+ },
1319
+ mode: 'HEALTH_CHECK',
1320
+ }),
1321
+ }).then(response => {
1322
+ if (!response.ok) {
1323
+ throw new Error(`Gemini credentials check failed: ${response.status}`);
1324
+ }
1325
+ });
1326
+ const timeout = sleep(GCP_CREDENTIALS_CHECK_TIMEOUT_MS).then(() => {
1327
+ throw new GcpCredentialsTimeoutError('Gemini credentials check timed out');
1328
+ });
1329
+ await Promise.race([probe, timeout]);
1330
+ return true;
1331
+ }
1332
+ catch {
1333
+ return false;
1334
+ }
1335
+ }
1336
+ export function getGeminiGoogleOAuthTokens() {
1337
+ try {
1338
+ const profileId = getResolvedProviderProfileId('gemini-google');
1339
+ const storage = getSecureStorage().read();
1340
+ const scoped = profileId ? storage?.providerProfileOauth?.[profileId] : null;
1341
+ if (scoped?.accessToken) {
1342
+ return scoped;
1343
+ }
1344
+ const fallback = Object.entries(storage?.providerProfileOauth ?? {}).find(([key, value]) => key.startsWith('gemini-google/') &&
1345
+ typeof value === 'object' &&
1346
+ value !== null &&
1347
+ typeof value.accessToken === 'string' &&
1348
+ value.accessToken.trim())?.[1];
1349
+ if (fallback?.accessToken) {
1350
+ return fallback;
1351
+ }
1352
+ return null;
1353
+ }
1354
+ catch {
1355
+ return null;
1356
+ }
1357
+ }
1358
+ export function saveGeminiGoogleOAuthTokens(tokens) {
1359
+ const secureStorage = getSecureStorage();
1360
+ const storageBackend = secureStorage.name;
1361
+ try {
1362
+ const storageData = secureStorage.read() || {};
1363
+ const profileId = getResolvedProviderProfileId('gemini-google') ??
1364
+ ensureProviderProfile('gemini-google').id;
1365
+ const nextOauth = {
1366
+ accessToken: tokens.accessToken,
1367
+ refreshToken: tokens.refreshToken,
1368
+ expiresAt: tokens.expiresAt,
1369
+ scopes: tokens.scopes,
1370
+ subscriptionType: null,
1371
+ rateLimitTier: null,
1372
+ projectId: tokens.projectId,
1373
+ };
1374
+ if (profileId) {
1375
+ ;
1376
+ storageData.providerProfileOauth = {
1377
+ ...(storageData.providerProfileOauth ?? {}),
1378
+ [profileId]: nextOauth,
1379
+ };
1380
+ }
1381
+ const updateStatus = secureStorage.update(storageData);
1382
+ logEvent(updateStatus.success
1383
+ ? 'tengu_gemini_google_oauth_tokens_saved'
1384
+ : 'tengu_gemini_google_oauth_tokens_save_failed', { storageBackend });
1385
+ return updateStatus;
1386
+ }
1387
+ catch (error) {
1388
+ logError(error);
1389
+ logEvent('tengu_gemini_google_oauth_tokens_save_exception', {
1390
+ storageBackend,
1391
+ error: errorMessage(error),
1392
+ });
1393
+ return { success: false, warning: 'Failed to save Gemini OAuth tokens' };
1394
+ }
1395
+ }
1396
+ async function refreshGeminiGoogleOAuthTokensIfNeeded() {
1397
+ const tokens = getGeminiGoogleOAuthTokens();
1398
+ if (!tokens?.refreshToken) {
1399
+ return tokens;
1400
+ }
1401
+ if (tokens.expiresAt && tokens.expiresAt > Date.now() + 60_000) {
1402
+ return tokens;
1403
+ }
1404
+ const response = await fetch(GEMINI_CLI_OAUTH_TOKEN_URL, {
1405
+ method: 'POST',
1406
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
1407
+ body: new URLSearchParams({
1408
+ grant_type: 'refresh_token',
1409
+ refresh_token: tokens.refreshToken,
1410
+ client_id: GEMINI_CLI_OAUTH_CLIENT_ID,
1411
+ client_secret: GEMINI_CLI_OAUTH_CLIENT_SECRET,
1412
+ }),
1413
+ });
1414
+ if (!response.ok) {
1415
+ return tokens;
1416
+ }
1417
+ const data = (await response.json());
1418
+ const refreshed = {
1419
+ ...tokens,
1420
+ accessToken: data.access_token,
1421
+ expiresAt: data.expires_in ? Date.now() + data.expires_in * 1000 : tokens.expiresAt,
1422
+ scopes: data.scope?.split(/\s+/).filter(Boolean) ?? tokens.scopes,
1423
+ };
1424
+ saveGeminiGoogleOAuthTokens(refreshed);
1425
+ return refreshed;
1426
+ }
1427
+ function quoteShellArg(value) {
1428
+ return `"${value.replace(/"/g, '\\"')}"`;
1429
+ }
1430
+ export function getGeminiGoogleAuthCommand() {
1431
+ const clientIdFile = process.env.GEMINI_OAUTH_CLIENT_SECRET_FILE ||
1432
+ process.env.GOOGLE_OAUTH_CLIENT_SECRET_FILE;
1433
+ const scopes = GEMINI_GOOGLE_AUTH_SCOPES.join(',');
1434
+ const clientIdArg = clientIdFile
1435
+ ? ` --client-id-file=${quoteShellArg(clientIdFile)}`
1436
+ : '';
1437
+ return `gcloud auth application-default login${clientIdArg} --scopes=${quoteShellArg(scopes)}`;
1438
+ }
1439
+ export async function refreshGeminiGoogleAuth() {
1440
+ return refreshGcpAuth(getGeminiGoogleAuthCommand());
1441
+ }
1442
+ export function getGeminiApiAccessToken() {
1443
+ return (process.env.GEMINI_API_KEY ||
1444
+ process.env.GOOGLE_API_KEY ||
1445
+ getStoredProviderApiKey('gemini-api', getResolvedProviderProfileId('gemini-api')) ||
1446
+ null);
1447
+ }
1448
+ export async function getGeminiGoogleAuthHeaders() {
1449
+ const explicitToken = process.env.GEMINI_OAUTH_TOKEN || process.env.GOOGLE_OAUTH_ACCESS_TOKEN;
1450
+ const headers = {
1451
+ 'Content-Type': 'application/json',
1452
+ };
1453
+ if (explicitToken) {
1454
+ headers.Authorization = `Bearer ${explicitToken}`;
1455
+ }
1456
+ else {
1457
+ const storedTokens = await refreshGeminiGoogleOAuthTokensIfNeeded();
1458
+ if (storedTokens?.accessToken) {
1459
+ headers.Authorization = `Bearer ${storedTokens.accessToken}`;
1460
+ const explicitProjectId = process.env.GEMINI_GOOGLE_PROJECT_ID?.trim();
1461
+ if (explicitProjectId) {
1462
+ headers['x-goog-user-project'] = explicitProjectId;
1463
+ }
1464
+ }
1465
+ else {
1466
+ const { GoogleAuth } = await import('google-auth-library');
1467
+ const auth = new GoogleAuth({
1468
+ scopes: GEMINI_GOOGLE_AUTH_SCOPES,
1469
+ });
1470
+ const client = await auth.getClient();
1471
+ const authHeaders = await client.getRequestHeaders();
1472
+ if (typeof authHeaders.forEach === 'function') {
1473
+ ;
1474
+ authHeaders.forEach((value, key) => {
1475
+ headers[key] = value;
1476
+ });
1477
+ }
1478
+ else {
1479
+ for (const [key, value] of Object.entries(authHeaders)) {
1480
+ if (Array.isArray(value)) {
1481
+ headers[key] = value.map(String).join(', ');
1482
+ }
1483
+ else if (value !== undefined && value !== null) {
1484
+ headers[key] = String(value);
1485
+ }
1486
+ }
1487
+ }
1488
+ }
1489
+ }
1490
+ const projectId = process.env.GEMINI_GOOGLE_PROJECT_ID?.trim() || undefined;
1491
+ if (projectId) {
1492
+ headers['x-goog-user-project'] = projectId;
1493
+ }
1494
+ return headers;
1495
+ }
1299
1496
  export function getZAIAccessToken() {
1300
1497
  return (process.env.ZAI_API_KEY ||
1301
1498
  getStoredProviderApiKey('zai', getResolvedProviderProfileId('zai')) ||
@@ -1310,12 +1507,20 @@ export function getOllamaAccessToken() {
1310
1507
  return 'ollama';
1311
1508
  }
1312
1509
  export function getOllamaCloudAccessToken() {
1313
- return process.env.OLLAMA_API_KEY || null;
1510
+ return (process.env.OLLAMA_API_KEY ||
1511
+ getStoredProviderApiKey('ollama-cloud', getResolvedProviderProfileId('ollama-cloud')) ||
1512
+ null);
1314
1513
  }
1315
1514
  export function getOpenAICompatibleAccessToken(provider = getAPIProvider()) {
1316
1515
  switch (provider) {
1317
1516
  case 'openrouter':
1318
1517
  return getOpenRouterAccessToken();
1518
+ case 'gemini-api':
1519
+ return getGeminiApiAccessToken();
1520
+ case 'gemini-google':
1521
+ return (process.env.GEMINI_OAUTH_TOKEN ||
1522
+ process.env.GOOGLE_OAUTH_ACCESS_TOKEN ||
1523
+ null);
1319
1524
  case 'zai':
1320
1525
  return getZAIAccessToken();
1321
1526
  case 'minimax':
@@ -50,14 +50,14 @@ export async function assertMinVersion() {
50
50
  if (versionConfig.minVersion &&
51
51
  lt(MACRO.VERSION, versionConfig.minVersion)) {
52
52
  // biome-ignore lint/suspicious/noConsole:: intentional console output
53
- console.error(`
54
- It looks like your version of Context Code (${MACRO.VERSION}) needs an update.
55
- A newer version (${versionConfig.minVersion} or higher) is required to continue.
56
-
57
- To update, please run:
58
- claude update
59
-
60
- This will ensure you have access to the latest features and improvements.
53
+ console.error(`
54
+ It looks like your version of Context Code (${MACRO.VERSION}) needs an update.
55
+ A newer version (${versionConfig.minVersion} or higher) is required to continue.
56
+
57
+ To update, please run:
58
+ claude update
59
+
60
+ This will ensure you have access to the latest features and improvements.
61
61
  `);
62
62
  gracefulShutdownSync(1);
63
63
  }
@@ -391,16 +391,16 @@ export async function installGlobalPackage(specificVersion) {
391
391
  currentVersion: MACRO.VERSION,
392
392
  });
393
393
  // biome-ignore lint/suspicious/noConsole:: intentional console output
394
- console.error(`
395
- Error: Windows NPM detected in WSL
396
-
397
- You're running Context Code in WSL but using the Windows NPM installation from /mnt/c/.
398
- This configuration is not supported for updates.
399
-
400
- To fix this issue:
401
- 1. Install Node.js within your Linux distribution: e.g. sudo apt install nodejs npm
402
- 2. Make sure Linux NPM is in your PATH before the Windows version
403
- 3. Try updating again with 'context update'
394
+ console.error(`
395
+ Error: Windows NPM detected in WSL
396
+
397
+ You're running Context Code in WSL but using the Windows NPM installation from /mnt/c/.
398
+ This configuration is not supported for updates.
399
+
400
+ To fix this issue:
401
+ 1. Install Node.js within your Linux distribution: e.g. sudo apt install nodejs npm
402
+ 2. Make sure Linux NPM is in your PATH before the Windows version
403
+ 3. Try updating again with 'context update'
404
404
  `);
405
405
  return 'install_failed';
406
406
  }