u-foo 2.2.4 → 2.3.1
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/SKILLS/ufoo/SKILL.md +56 -12
- package/SKILLS/uinit/SKILL.md +3 -2
- package/modules/AGENTS.template.md +2 -1
- package/modules/bus/README.md +1 -1
- package/modules/context/SKILLS/uctx/SKILL.md +6 -4
- package/package.json +1 -1
- package/src/agent/activityStatePublisher.js +6 -2
- package/src/agent/codexThreadProvider.js +2 -2
- package/src/agent/controllerToolExecutor.js +24 -1
- package/src/agent/credentials/claude.js +85 -16
- package/src/agent/credentials/codex.js +251 -23
- package/src/agent/defaultBootstrap.js +3 -1
- package/src/agent/directAuthStatus.js +264 -0
- package/src/agent/internalRunner.js +18 -12
- package/src/agent/loopObservability.js +10 -0
- package/src/agent/loopRuntime.js +19 -0
- package/src/agent/notifier.js +12 -3
- package/src/agent/ufooAgent.js +43 -13
- package/src/agent/upstreamTransport.js +23 -8
- package/src/bus/index.js +6 -1
- package/src/bus/message.js +156 -8
- package/src/chat/commandExecutor.js +187 -7
- package/src/chat/commands.js +23 -4
- package/src/chat/completionController.js +30 -7
- package/src/chat/index.js +3 -5
- package/src/cli/groupCoreCommands.js +5 -0
- package/src/cli.js +309 -0
- package/src/code/UCODE_PROMPT.md +3 -2
- package/src/code/prompts/ufoo.js +3 -2
- package/src/config.js +16 -3
- package/src/context/doctor.js +1 -1
- package/src/daemon/groupOrchestrator.js +13 -9
- package/src/daemon/promptRequest.js +11 -2
- package/src/daemon/soloBootstrap.js +2 -0
- package/src/group/bootstrap.js +1 -1
- package/src/group/promptProfiles.js +106 -22
- package/src/group/templates.js +1 -0
- package/src/init/index.js +4 -0
- package/src/memory/historySearch.js +308 -0
- package/src/memory/index.js +653 -8
- package/src/providerapi/redactor.js +4 -1
- package/src/status/index.js +24 -1
- package/src/tools/handlers/memory.js +168 -0
- package/src/tools/index.js +12 -0
- package/src/tools/registry.js +12 -0
- package/src/tools/schemaFixtures.js +213 -0
- package/src/tools/tier1/editMemory.js +14 -0
- package/src/tools/tier1/forget.js +14 -0
- package/src/tools/tier1/recall.js +14 -0
- package/src/tools/tier1/remember.js +14 -0
- package/src/tools/tier1/searchHistory.js +14 -0
- package/src/tools/tier1/searchMemory.js +14 -0
- package/templates/groups/build-lane.json +44 -6
- package/templates/groups/build-ultra.json +6 -5
- package/templates/groups/design-system.json +84 -0
- package/templates/groups/product-discovery.json +9 -4
- package/templates/groups/ui-plan-review.json +84 -0
- package/templates/groups/ui-polish.json +6 -2
- package/templates/groups/verify-ship.json +9 -4
package/SKILLS/ufoo/SKILL.md
CHANGED
|
@@ -8,11 +8,12 @@ description: |
|
|
|
8
8
|
|
|
9
9
|
# ufoo — Unified Agent Protocol
|
|
10
10
|
|
|
11
|
-
ufoo is the multi-agent coordination layer. It provides
|
|
11
|
+
ufoo is the multi-agent coordination layer. It provides four capabilities:
|
|
12
12
|
|
|
13
|
-
1. **Context Decisions** —
|
|
14
|
-
2. **
|
|
15
|
-
3. **
|
|
13
|
+
1. **Context Decisions** — Sparse log of major plan-level choices shared across agents
|
|
14
|
+
2. **Shared Memory** — Durable, low-noise project facts shared across agents
|
|
15
|
+
3. **Event Bus** — Inter-agent messaging
|
|
16
|
+
4. **Initialization** — Project setup for ufoo modules
|
|
16
17
|
|
|
17
18
|
## Session Marker
|
|
18
19
|
|
|
@@ -26,13 +27,14 @@ When you see a probe marker command like `/ufoo <marker>` (Claude) or `$ufoo <ma
|
|
|
26
27
|
|
|
27
28
|
**"Only record decisions that matter beyond this session."**
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
The default is **no new decision**. Record one only for important, plan-level knowledge that other agents or your future self will need.
|
|
30
31
|
|
|
31
32
|
- **Always record**: architectural choices, plan-level decisions with multiple options, cross-agent coordination decisions, trade-off analysis where alternatives were considered and rejected
|
|
32
33
|
- **Also record**: design patterns that set precedent, integration contracts between systems, decisions that constrain future work
|
|
33
|
-
- **Do NOT record**: routine bug fixes, simple implementation details, trivial observations, findings that only matter within the current task
|
|
34
|
-
- **
|
|
35
|
-
- **
|
|
34
|
+
- **Do NOT record**: routine bug fixes, simple implementation details, trivial observations, generic planning/evaluation/recommendation requests, or findings that only matter within the current task
|
|
35
|
+
- **Prefer shared memory**: durable project facts and long-lived factual constraints belong in shared memory, not decisions
|
|
36
|
+
- **Write the decision BEFORE acting on it** — but only after the high bar above is clearly met
|
|
37
|
+
- **Rule of thumb**: if another agent would not need this as a future constraint, do not write a decision
|
|
36
38
|
|
|
37
39
|
### Commands
|
|
38
40
|
|
|
@@ -75,9 +77,51 @@ What must follow from this?
|
|
|
75
77
|
|
|
76
78
|
**NEVER resolve blindly.** Reading the title is not enough.
|
|
77
79
|
|
|
80
|
+
### Read-First Rule
|
|
81
|
+
|
|
82
|
+
Shared context is **read-first**, not write-only:
|
|
83
|
+
|
|
84
|
+
1. At session start or before related work, read open decisions first.
|
|
85
|
+
2. Do not create a new decision just to persist ordinary work state.
|
|
86
|
+
3. Consume shared memory via prompt prefix / `recall` / `search_memory` before writing new memory.
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 2. Shared Memory
|
|
91
|
+
|
|
92
|
+
Shared memory records durable project facts only. It is not a scratchpad, progress log, user-preference store, or replacement for decisions.
|
|
93
|
+
|
|
94
|
+
### When to Record
|
|
95
|
+
|
|
96
|
+
- **Record**: permanent project invariants, external ownership facts, integration contracts, long-lived process constraints
|
|
97
|
+
- **Do NOT record**: current task status, transient observations, "today/current/recent" facts, agent feedback, routine findings, or anything likely to expire
|
|
98
|
+
- **Read first**: if memory may already exist, use `recall` / `search_memory` before `remember` or `edit_memory`
|
|
99
|
+
- **Prefer edit over duplicate**: update an existing memory when the fact already exists but wording changed
|
|
100
|
+
|
|
101
|
+
### Commands
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
ufoo memory add "Title" --body "Durable fact body" --tags infra,billing
|
|
105
|
+
ufoo memory list [--tag infra] [--all]
|
|
106
|
+
ufoo memory show mem-0001
|
|
107
|
+
ufoo memory edit mem-0001
|
|
108
|
+
ufoo memory forget mem-0001
|
|
109
|
+
ufoo memory rebuild-index
|
|
110
|
+
ufoo memory audit mem-0001
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Agent Tools
|
|
114
|
+
|
|
115
|
+
- `remember` — write a new durable memory fact
|
|
116
|
+
- `recall` — read memory by id or tags
|
|
117
|
+
- `search_memory` — search memory before writing or when more context is needed
|
|
118
|
+
- `search_history` — search local Claude/Codex session history as redacted evidence
|
|
119
|
+
- `edit_memory` — directly update any existing memory, with optional `expected_updated_at`
|
|
120
|
+
- `forget` — archive an obsolete or polluted memory entry
|
|
121
|
+
|
|
78
122
|
---
|
|
79
123
|
|
|
80
|
-
##
|
|
124
|
+
## 3. Event Bus (ubus)
|
|
81
125
|
|
|
82
126
|
### Commands
|
|
83
127
|
|
|
@@ -122,7 +166,7 @@ Notes:
|
|
|
122
166
|
|
|
123
167
|
---
|
|
124
168
|
|
|
125
|
-
##
|
|
169
|
+
## 4. Message Format
|
|
126
170
|
|
|
127
171
|
Bus messages use a unified prefix format to distinguish sources:
|
|
128
172
|
|
|
@@ -134,7 +178,7 @@ When you see `[manual]<to:xxx>`, it's a direct user instruction to an agent —
|
|
|
134
178
|
|
|
135
179
|
---
|
|
136
180
|
|
|
137
|
-
##
|
|
181
|
+
## 5. Team Activity (Input History)
|
|
138
182
|
|
|
139
183
|
Your bootstrap prompt may include a `## Team Activity` section showing recent prompts sent to all agents. Use this to understand:
|
|
140
184
|
- What each agent is currently working on
|
|
@@ -150,7 +194,7 @@ ufoo history prompt [limit] # Render as injectable prompt block
|
|
|
150
194
|
|
|
151
195
|
---
|
|
152
196
|
|
|
153
|
-
##
|
|
197
|
+
## 6. Initialization (uinit)
|
|
154
198
|
|
|
155
199
|
Trigger: `/uinit` or `/ufoo init`
|
|
156
200
|
|
package/SKILLS/uinit/SKILL.md
CHANGED
|
@@ -29,7 +29,7 @@ Please select modules to enable:
|
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
Options:
|
|
32
|
-
- `context` (recommended) - Shared context, decision
|
|
32
|
+
- `context` (recommended) - Shared context, sparse decision log for major plan-level choices
|
|
33
33
|
- `bus` (recommended) - Multi-agent communication, task delegation, message passing
|
|
34
34
|
- `resources` (optional) - UI tone guide, icon library
|
|
35
35
|
|
|
@@ -61,6 +61,7 @@ fi
|
|
|
61
61
|
=== ufoo initialization complete ===
|
|
62
62
|
|
|
63
63
|
Enabled modules:
|
|
64
|
+
✓ core memory → .ufoo/memory/
|
|
64
65
|
✓ context → .ufoo/context/
|
|
65
66
|
✓ bus → .ufoo/bus/ + .ufoo/agent/
|
|
66
67
|
|
|
@@ -73,6 +74,6 @@ Next steps:
|
|
|
73
74
|
|
|
74
75
|
## Notes
|
|
75
76
|
|
|
76
|
-
- If .ufoo/context, .ufoo/bus, or .ufoo/agent already exists, skip creation
|
|
77
|
+
- If .ufoo/memory, .ufoo/context, .ufoo/bus, or .ufoo/agent already exists, skip creation
|
|
77
78
|
- After initialization, reuse existing subscriber ID first, join only as fallback (if bus enabled)
|
|
78
79
|
- AGENTS.md will have protocol description block injected
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<!-- ufoo -->
|
|
2
2
|
## ufoo Agent Protocol
|
|
3
3
|
|
|
4
|
-
> **
|
|
4
|
+
> **Default: do not write a decision.** Record one only for important, plan-level knowledge that should constrain future work: architectural choices, trade-off analysis, cross-agent coordination, or precedent-setting integration contracts. NOT for routine findings, simple fixes, or because the user asked for a plan/evaluation/recommendation. Durable project facts belong in shared memory, not decisions. → `ufoo ctx decisions new "Title"` BEFORE acting only when that high bar is met.
|
|
5
|
+
> **Read shared memory before writing it.** Durable facts live in `.ufoo/memory/`; use `ufoo memory list/show`, `recall`, `search_memory`, or redacted `search_history` evidence before `remember` / `edit_memory`.
|
|
5
6
|
> **Auto-execute bus messages.** On `ubus`: execute tasks immediately, reply to sender, then `ufoo bus ack`. Never ask the user.
|
|
6
7
|
> **Full protocol**: `/ufoo` skill (auto-loaded on session start). Docs: `.ufoo/docs/`
|
|
7
8
|
<!-- /ufoo -->
|
package/modules/bus/README.md
CHANGED
|
@@ -134,7 +134,7 @@ Examples:
|
|
|
134
134
|
|
|
135
135
|
| Module | Problem Solved |
|
|
136
136
|
|--------|----------------|
|
|
137
|
-
| context | Shared context, decision
|
|
137
|
+
| context | Shared context, sparse decision log for major plan-level choices |
|
|
138
138
|
| bus | Real-time communication, task delegation, message passing |
|
|
139
139
|
|
|
140
140
|
Both are independent peer modules that can be used separately or together.
|
|
@@ -13,13 +13,15 @@ description: |
|
|
|
13
13
|
Fast context check for daily use. Run at session start or anytime.
|
|
14
14
|
|
|
15
15
|
Pre-flight reminder:
|
|
16
|
-
-
|
|
17
|
-
|
|
16
|
+
- Default is no new decision.
|
|
17
|
+
- Write a decision only for important architectural choices, trade-off outcomes, cross-agent coordination, or precedent-setting integration contracts.
|
|
18
|
+
- Do NOT write decisions for routine tasks, simple bug fixes, trivial findings, or generic plan/evaluation/recommendation requests.
|
|
19
|
+
- Durable project facts belong in shared memory, not decisions.
|
|
18
20
|
Use: `ufoo ctx decisions new "<Title>"`
|
|
19
21
|
|
|
20
22
|
## Decision format (canonical)
|
|
21
23
|
|
|
22
|
-
|
|
24
|
+
The context module tracks decisions only. Durable shared facts belong in shared memory. Decisions live at:
|
|
23
25
|
`<project>/.ufoo/context/decisions/`
|
|
24
26
|
|
|
25
27
|
Decision index (JSONL):
|
|
@@ -36,7 +38,7 @@ Each JSONL row includes:
|
|
|
36
38
|
- `file` (decision filename)
|
|
37
39
|
- `author` (decision author or resolver)
|
|
38
40
|
|
|
39
|
-
Create a new decision (
|
|
41
|
+
Create a new decision (only when the high-threshold rule above requires it):
|
|
40
42
|
```bash
|
|
41
43
|
ufoo ctx decisions new "Short Title"
|
|
42
44
|
```
|
package/package.json
CHANGED
|
@@ -12,6 +12,7 @@ const { writeActivityState } = require("./activityStateWriter");
|
|
|
12
12
|
* @param {string} options.subscriber - Subscriber ID (e.g. "claude-code:abc123")
|
|
13
13
|
* @param {string} options.projectRoot - Project root (unused, kept for API compat)
|
|
14
14
|
* @param {boolean} [options.force=true] - Force overwrite priority-protected states
|
|
15
|
+
* publish(state, extra, { force }) can override this default for one transition.
|
|
15
16
|
*/
|
|
16
17
|
function createActivityStatePublisher(options = {}) {
|
|
17
18
|
const {
|
|
@@ -22,10 +23,13 @@ function createActivityStatePublisher(options = {}) {
|
|
|
22
23
|
|
|
23
24
|
let lastState = "";
|
|
24
25
|
|
|
25
|
-
function publish(state, extra = {}) {
|
|
26
|
+
function publish(state, extra = {}, publishOptions = {}) {
|
|
26
27
|
if (state === lastState) return false;
|
|
27
28
|
const since = extra.since || undefined;
|
|
28
|
-
const
|
|
29
|
+
const effectiveForce = typeof publishOptions.force === "boolean"
|
|
30
|
+
? publishOptions.force
|
|
31
|
+
: force;
|
|
32
|
+
const changed = writeActivityState(agentsFile, subscriber, state, { since, force: effectiveForce });
|
|
29
33
|
if (!changed) return false;
|
|
30
34
|
lastState = state;
|
|
31
35
|
// Write to bus events directory for daemon bridge to pick up.
|
|
@@ -61,7 +61,7 @@ async function* defaultCodexTransportStreamFactory({
|
|
|
61
61
|
});
|
|
62
62
|
if (!result.ok) {
|
|
63
63
|
const err = new Error(result.error || "Codex upstream request failed");
|
|
64
|
-
err.code = "CODEX_UPSTREAM_FAILED";
|
|
64
|
+
err.code = result.errorCode || "CODEX_UPSTREAM_FAILED";
|
|
65
65
|
throw err;
|
|
66
66
|
}
|
|
67
67
|
|
|
@@ -145,7 +145,7 @@ class CodexThreadProvider {
|
|
|
145
145
|
this.cwd = cwd;
|
|
146
146
|
this.extraArgs = Array.isArray(extraArgs) ? extraArgs.slice() : [];
|
|
147
147
|
this.streamFactory = streamFactory;
|
|
148
|
-
this.sdk = sdk || resolveCodexSdk();
|
|
148
|
+
this.sdk = sdk || (streamFactory === defaultCodexStreamFactory ? resolveCodexSdk() : null);
|
|
149
149
|
this.tools = Array.isArray(tools) ? tools.slice() : [];
|
|
150
150
|
}
|
|
151
151
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const EventBus = require("../bus");
|
|
4
|
+
const { getToolDefinition, CALLER_TIERS } = require("../tools");
|
|
4
5
|
const { dispatchMessageHandler } = require("../tools/handlers/dispatchMessage");
|
|
5
6
|
const { ackBusHandler } = require("../tools/handlers/ackBus");
|
|
6
7
|
|
|
@@ -145,6 +146,25 @@ async function handleLaunchAgent(ctx, args) {
|
|
|
145
146
|
};
|
|
146
147
|
}
|
|
147
148
|
|
|
149
|
+
async function handleSharedRegistryTool(ctx, name, args, audit = {}) {
|
|
150
|
+
const definition = getToolDefinition(name);
|
|
151
|
+
if (!definition || typeof definition.handler !== "function") {
|
|
152
|
+
throw buildStructuredError("unsupported_tool", `unsupported controller tool: ${name}`);
|
|
153
|
+
}
|
|
154
|
+
if (!definition.allowed_tiers.includes(CALLER_TIERS.CONTROLLER)) {
|
|
155
|
+
throw buildStructuredError("forbidden_caller_tier", `controller is not allowed to invoke tool: ${name}`);
|
|
156
|
+
}
|
|
157
|
+
const eventBus = ctx.eventBus || new EventBus(ctx.projectRoot);
|
|
158
|
+
return definition.handler({
|
|
159
|
+
projectRoot: ctx.projectRoot,
|
|
160
|
+
subscriber: ctx.subscriber || "ufoo-agent",
|
|
161
|
+
caller_tier: CALLER_TIERS.CONTROLLER,
|
|
162
|
+
eventBus,
|
|
163
|
+
turn_id: audit.turn_id || "",
|
|
164
|
+
tool_call_id: audit.tool_call_id || "",
|
|
165
|
+
}, args);
|
|
166
|
+
}
|
|
167
|
+
|
|
148
168
|
async function executeControllerTool(ctx, toolCall = {}) {
|
|
149
169
|
const observer = ctx.observer || { emit: () => {}, audit: () => {} };
|
|
150
170
|
const name = String(toolCall.name || "").trim();
|
|
@@ -169,7 +189,10 @@ async function executeControllerTool(ctx, toolCall = {}) {
|
|
|
169
189
|
} else if (name === "launch_agent") {
|
|
170
190
|
result = await handleLaunchAgent(ctx, args);
|
|
171
191
|
} else {
|
|
172
|
-
|
|
192
|
+
result = await handleSharedRegistryTool(ctx, name, args, {
|
|
193
|
+
turn_id: turnId,
|
|
194
|
+
tool_call_id: toolCallId,
|
|
195
|
+
});
|
|
173
196
|
}
|
|
174
197
|
|
|
175
198
|
observer.emit("tool_call_finished", {
|
|
@@ -25,6 +25,7 @@ function resolveClaudeOauthPaths(options = {}) {
|
|
|
25
25
|
const configDir = String(options.configDir || defaultClaudeConfigDir()).trim() || defaultClaudeConfigDir();
|
|
26
26
|
const profile = String(options.profile || "").trim();
|
|
27
27
|
const explicitTokenPath = String(options.tokenPath || "").trim();
|
|
28
|
+
const explicitSettingsPath = String(options.settingsPath || "").trim();
|
|
28
29
|
const profileDir = profile ? path.join(configDir, "profiles", profile) : configDir;
|
|
29
30
|
const tokenPath = explicitTokenPath || path.join(profileDir, "oauth.json");
|
|
30
31
|
return {
|
|
@@ -33,9 +34,17 @@ function resolveClaudeOauthPaths(options = {}) {
|
|
|
33
34
|
profileDir,
|
|
34
35
|
tokenPath,
|
|
35
36
|
lockPath: `${tokenPath}.lock`,
|
|
37
|
+
settingsPath: explicitSettingsPath || path.join(configDir, "settings.json"),
|
|
36
38
|
};
|
|
37
39
|
}
|
|
38
40
|
|
|
41
|
+
function firstString(...values) {
|
|
42
|
+
for (const value of values) {
|
|
43
|
+
if (typeof value === "string" && value.trim()) return value.trim();
|
|
44
|
+
}
|
|
45
|
+
return "";
|
|
46
|
+
}
|
|
47
|
+
|
|
39
48
|
function classifyTokenState(expiresAtMs, nowMs, refreshWindowMs) {
|
|
40
49
|
if (!Number.isFinite(expiresAtMs)) return "invalid";
|
|
41
50
|
if (expiresAtMs <= nowMs) return "expired";
|
|
@@ -208,6 +217,61 @@ class ClaudeUpstreamCredentialResolver {
|
|
|
208
217
|
};
|
|
209
218
|
}
|
|
210
219
|
|
|
220
|
+
readSettingsEnv() {
|
|
221
|
+
let raw;
|
|
222
|
+
try {
|
|
223
|
+
raw = JSON.parse(this.fs.readFileSync(this.paths.settingsPath, "utf8"));
|
|
224
|
+
} catch {
|
|
225
|
+
return {};
|
|
226
|
+
}
|
|
227
|
+
const env = raw && raw.env && typeof raw.env === "object" && !Array.isArray(raw.env)
|
|
228
|
+
? raw.env
|
|
229
|
+
: {};
|
|
230
|
+
const apiKeySource = firstString(env.ANTHROPIC_API_KEY)
|
|
231
|
+
? "settings:ANTHROPIC_API_KEY"
|
|
232
|
+
: (firstString(env.CLAUDE_API_KEY) ? "settings:CLAUDE_API_KEY" : "");
|
|
233
|
+
return {
|
|
234
|
+
apiKey: firstString(env.ANTHROPIC_API_KEY, env.CLAUDE_API_KEY),
|
|
235
|
+
apiKeySource,
|
|
236
|
+
authToken: firstString(env.ANTHROPIC_AUTH_TOKEN),
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
buildApiKeyCredential(apiKey, source, credentialPath = "") {
|
|
241
|
+
return buildCredentialDescriptor({
|
|
242
|
+
provider: "claude",
|
|
243
|
+
credentialKind: "api-key",
|
|
244
|
+
source,
|
|
245
|
+
apiKey,
|
|
246
|
+
tokenType: "Bearer",
|
|
247
|
+
state: "fresh",
|
|
248
|
+
refreshable: false,
|
|
249
|
+
profile: this.paths.profile,
|
|
250
|
+
credentialPath,
|
|
251
|
+
nowMs: this.now(),
|
|
252
|
+
refreshWindowMs: this.refreshWindowMs,
|
|
253
|
+
});
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
buildAuthTokenCredential(accessToken, source, credentialPath = "") {
|
|
257
|
+
return buildCredentialDescriptor({
|
|
258
|
+
provider: "claude",
|
|
259
|
+
credentialKind: "oauth",
|
|
260
|
+
source,
|
|
261
|
+
accessToken,
|
|
262
|
+
tokenType: "Bearer",
|
|
263
|
+
state: "fresh",
|
|
264
|
+
refreshable: false,
|
|
265
|
+
profile: this.paths.profile,
|
|
266
|
+
credentialPath,
|
|
267
|
+
nowMs: this.now(),
|
|
268
|
+
refreshWindowMs: this.refreshWindowMs,
|
|
269
|
+
metadata: {
|
|
270
|
+
tokenPath: credentialPath,
|
|
271
|
+
},
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
|
|
211
275
|
buildResolvedCredential(tokenRecord) {
|
|
212
276
|
return buildCredentialDescriptor({
|
|
213
277
|
provider: "claude",
|
|
@@ -269,21 +333,26 @@ class ClaudeUpstreamCredentialResolver {
|
|
|
269
333
|
}
|
|
270
334
|
|
|
271
335
|
async resolveCredentials() {
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
336
|
+
const anthropicApiKey = firstString(this.env.ANTHROPIC_API_KEY);
|
|
337
|
+
const claudeApiKey = firstString(this.env.CLAUDE_API_KEY);
|
|
338
|
+
if (anthropicApiKey || claudeApiKey) {
|
|
339
|
+
return this.buildApiKeyCredential(
|
|
340
|
+
anthropicApiKey || claudeApiKey,
|
|
341
|
+
anthropicApiKey ? "env:ANTHROPIC_API_KEY" : "env:CLAUDE_API_KEY",
|
|
342
|
+
);
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
const authToken = firstString(this.env.ANTHROPIC_AUTH_TOKEN);
|
|
346
|
+
if (authToken) {
|
|
347
|
+
return this.buildAuthTokenCredential(authToken, "env:ANTHROPIC_AUTH_TOKEN");
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
const settingsEnv = this.readSettingsEnv();
|
|
351
|
+
if (settingsEnv.apiKey) {
|
|
352
|
+
return this.buildApiKeyCredential(settingsEnv.apiKey, settingsEnv.apiKeySource || "settings:ANTHROPIC_API_KEY", this.paths.settingsPath);
|
|
353
|
+
}
|
|
354
|
+
if (settingsEnv.authToken) {
|
|
355
|
+
return this.buildAuthTokenCredential(settingsEnv.authToken, "settings:ANTHROPIC_AUTH_TOKEN", this.paths.settingsPath);
|
|
287
356
|
}
|
|
288
357
|
|
|
289
358
|
let tokenRecord;
|
|
@@ -291,7 +360,7 @@ class ClaudeUpstreamCredentialResolver {
|
|
|
291
360
|
tokenRecord = this.readTokenFile();
|
|
292
361
|
} catch (err) {
|
|
293
362
|
if (err && err.code === "ENOENT") {
|
|
294
|
-
const missing = new Error("Claude
|
|
363
|
+
const missing = new Error("Claude credentials not found in environment, Claude settings, or OAuth token file");
|
|
295
364
|
missing.code = "CLAUDE_AUTH_UNAVAILABLE";
|
|
296
365
|
throw missing;
|
|
297
366
|
}
|