@alfe.ai/claude-code-host 0.1.2 → 0.1.4
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/host-config.cjs +27 -18
- package/dist/host-config.js +27 -18
- package/dist/index.d.cts +109 -1
- package/dist/index.d.ts +109 -1
- package/package.json +2 -2
package/dist/host-config.cjs
CHANGED
|
@@ -463,6 +463,7 @@ var SessionDriver = class {
|
|
|
463
463
|
"--allowedTools",
|
|
464
464
|
allowed
|
|
465
465
|
];
|
|
466
|
+
if (params.model) args.push("--model", params.model);
|
|
466
467
|
if (params.claudeSessionId) args.push("--resume", params.claudeSessionId);
|
|
467
468
|
if (params.mcpConfigPath) args.push("--mcp-config", params.mcpConfigPath);
|
|
468
469
|
if (params.appendSystemPrompt) args.push("--append-system-prompt", params.appendSystemPrompt);
|
|
@@ -792,8 +793,20 @@ const VOICE_REPLY_SYSTEM_PROMPT = [
|
|
|
792
793
|
].join("\n");
|
|
793
794
|
/** Cross-agent tool steering (every turn). Mirrors CROSS_AGENT_TOOLS_SYSTEM_PROMPT. */
|
|
794
795
|
const CROSS_AGENT_TOOLS_SYSTEM_PROMPT = ["Cross-agent messaging: to contact another Alfe agent (IDs like agt_…), use list_agents to discover and message_agent to send.", "The runtime's built-in session tools do NOT know Alfe agent IDs and will fail — never use them to reach another agent."].join("\n");
|
|
795
|
-
/**
|
|
796
|
-
|
|
796
|
+
/**
|
|
797
|
+
* Short, AUTHORITATIVE persona pointer for `--append-system-prompt`. The full
|
|
798
|
+
* persona (SOUL/IDENTITY/AGENTS/…) is delivered as the workspace `CLAUDE.md`,
|
|
799
|
+
* which Claude Code auto-loads every turn — so we do NOT re-dump it into the
|
|
800
|
+
* system prompt (doing both double-injected the persona, wasting tokens and
|
|
801
|
+
* risking drift). This system-level pointer just establishes the framing that
|
|
802
|
+
* CLAUDE.md-as-project-memory can't guarantee on its own: this is an Alfe chat
|
|
803
|
+
* agent, not a coding session.
|
|
804
|
+
*/
|
|
805
|
+
const PERSONA_POINTER_SYSTEM_PROMPT = [
|
|
806
|
+
"You are an Alfe agent replying to a user over a chat bridge — NOT an interactive coding session.",
|
|
807
|
+
"Your identity, persona, voice, and operating instructions live in CLAUDE.md and the other files in your workspace.",
|
|
808
|
+
"Fully embody that persona in how you speak and act; respond AS that agent, not as a generic coding assistant."
|
|
809
|
+
].join("\n");
|
|
797
810
|
/**
|
|
798
811
|
* One FIFO backlog PER claude-session key. Unlike openclaw-chat's single
|
|
799
812
|
* per-daemon queue, the Claude Code host spawns a distinct `claude -p` per
|
|
@@ -982,7 +995,7 @@ var ClaudeCodeHost = class {
|
|
|
982
995
|
} catch (err) {
|
|
983
996
|
this.log.warn(`[claude-host] memoryLoadContext failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
|
|
984
997
|
}
|
|
985
|
-
const appendSystemPrompt =
|
|
998
|
+
const appendSystemPrompt = this.buildSystemPrompt(memoryContext, isVoice);
|
|
986
999
|
const claudeSessionId = this.claudeSessionIds.get(bareSessionId) ?? null;
|
|
987
1000
|
const driver = this.makeDriver();
|
|
988
1001
|
this.runningTurns.set(sessionKey, req.id);
|
|
@@ -995,6 +1008,7 @@ var ClaudeCodeHost = class {
|
|
|
995
1008
|
cwd: this.cfg.workspace,
|
|
996
1009
|
...this.cfg.mcpConfigPath ? { mcpConfigPath: this.cfg.mcpConfigPath } : {},
|
|
997
1010
|
...appendSystemPrompt ? { appendSystemPrompt } : {},
|
|
1011
|
+
...this.cfg.model ? { model: this.cfg.model } : {},
|
|
998
1012
|
onEmission: (emission) => {
|
|
999
1013
|
this.forwardEmission(runId, sessionKey, emission);
|
|
1000
1014
|
}
|
|
@@ -1105,7 +1119,11 @@ var ClaudeCodeHost = class {
|
|
|
1105
1119
|
}
|
|
1106
1120
|
async handleSessionsList(req) {
|
|
1107
1121
|
const params = req.params;
|
|
1108
|
-
const sessions = await listSessions(
|
|
1122
|
+
const sessions = await listSessions({
|
|
1123
|
+
channel: params.channel,
|
|
1124
|
+
tenantId: params.tenantId,
|
|
1125
|
+
userId: params.userId
|
|
1126
|
+
});
|
|
1109
1127
|
this.chat.sendResponse(req.id, true, { sessions });
|
|
1110
1128
|
}
|
|
1111
1129
|
async handleSessionsGet(req) {
|
|
@@ -1139,23 +1157,13 @@ var ClaudeCodeHost = class {
|
|
|
1139
1157
|
activity: session.activity ?? []
|
|
1140
1158
|
});
|
|
1141
1159
|
}
|
|
1142
|
-
|
|
1143
|
-
const parts = [];
|
|
1144
|
-
const persona = await this.readPersona();
|
|
1145
|
-
if (persona) parts.push(persona);
|
|
1160
|
+
buildSystemPrompt(memoryContext, isVoice) {
|
|
1161
|
+
const parts = [PERSONA_POINTER_SYSTEM_PROMPT];
|
|
1146
1162
|
if (memoryContext) parts.push(`# Relevant memory\n\n${memoryContext}`);
|
|
1147
1163
|
if (isVoice) parts.push(VOICE_REPLY_SYSTEM_PROMPT);
|
|
1148
1164
|
parts.push(CROSS_AGENT_TOOLS_SYSTEM_PROMPT);
|
|
1149
1165
|
return parts.join("\n\n");
|
|
1150
1166
|
}
|
|
1151
|
-
async readPersona() {
|
|
1152
|
-
const chunks = [];
|
|
1153
|
-
for (const file of PERSONA_FILES) try {
|
|
1154
|
-
const text = await (0, node_fs_promises.readFile)((0, node_path.join)(this.cfg.workspace, file), "utf-8");
|
|
1155
|
-
if (text.trim()) chunks.push(text.trim());
|
|
1156
|
-
} catch {}
|
|
1157
|
-
return chunks.join("\n\n");
|
|
1158
|
-
}
|
|
1159
1167
|
async buildHistoryPreamble(bareSessionId) {
|
|
1160
1168
|
const session = await getSession(bareSessionId);
|
|
1161
1169
|
if (!session || session.messages.length === 0) return "";
|
|
@@ -1165,7 +1173,7 @@ var ClaudeCodeHost = class {
|
|
|
1165
1173
|
}
|
|
1166
1174
|
async ensureSession(bareSessionId, params) {
|
|
1167
1175
|
if (await getSession(bareSessionId)) return;
|
|
1168
|
-
await createSession(bareSessionId, params.agentId, params.clientType ?? "chat", params.tenantId, params.
|
|
1176
|
+
await createSession(bareSessionId, params.agentId, params.clientType ?? "chat", params.tenantId, params.userId);
|
|
1169
1177
|
}
|
|
1170
1178
|
async loadClaudeSessionIds() {
|
|
1171
1179
|
try {
|
|
@@ -1217,7 +1225,8 @@ function resolveHostConfig() {
|
|
|
1217
1225
|
apiUrl: resolved.apiUrl,
|
|
1218
1226
|
workspace: resolved.workspacePath,
|
|
1219
1227
|
mcpConfigPath: (0, node_path.join)((0, node_os.homedir)(), ".claude-code", "mcp-config.json"),
|
|
1220
|
-
claudeSessionsPath: (0, node_path.join)((0, node_os.homedir)(), ".alfe", "claude-code", "sessions.json")
|
|
1228
|
+
claudeSessionsPath: (0, node_path.join)((0, node_os.homedir)(), ".alfe", "claude-code", "sessions.json"),
|
|
1229
|
+
...process.env.ALFE_DEFAULT_MODEL?.trim() ? { model: process.env.ALFE_DEFAULT_MODEL.trim() } : {}
|
|
1221
1230
|
};
|
|
1222
1231
|
}
|
|
1223
1232
|
//#endregion
|
package/dist/host-config.js
CHANGED
|
@@ -463,6 +463,7 @@ var SessionDriver = class {
|
|
|
463
463
|
"--allowedTools",
|
|
464
464
|
allowed
|
|
465
465
|
];
|
|
466
|
+
if (params.model) args.push("--model", params.model);
|
|
466
467
|
if (params.claudeSessionId) args.push("--resume", params.claudeSessionId);
|
|
467
468
|
if (params.mcpConfigPath) args.push("--mcp-config", params.mcpConfigPath);
|
|
468
469
|
if (params.appendSystemPrompt) args.push("--append-system-prompt", params.appendSystemPrompt);
|
|
@@ -792,8 +793,20 @@ const VOICE_REPLY_SYSTEM_PROMPT = [
|
|
|
792
793
|
].join("\n");
|
|
793
794
|
/** Cross-agent tool steering (every turn). Mirrors CROSS_AGENT_TOOLS_SYSTEM_PROMPT. */
|
|
794
795
|
const CROSS_AGENT_TOOLS_SYSTEM_PROMPT = ["Cross-agent messaging: to contact another Alfe agent (IDs like agt_…), use list_agents to discover and message_agent to send.", "The runtime's built-in session tools do NOT know Alfe agent IDs and will fail — never use them to reach another agent."].join("\n");
|
|
795
|
-
/**
|
|
796
|
-
|
|
796
|
+
/**
|
|
797
|
+
* Short, AUTHORITATIVE persona pointer for `--append-system-prompt`. The full
|
|
798
|
+
* persona (SOUL/IDENTITY/AGENTS/…) is delivered as the workspace `CLAUDE.md`,
|
|
799
|
+
* which Claude Code auto-loads every turn — so we do NOT re-dump it into the
|
|
800
|
+
* system prompt (doing both double-injected the persona, wasting tokens and
|
|
801
|
+
* risking drift). This system-level pointer just establishes the framing that
|
|
802
|
+
* CLAUDE.md-as-project-memory can't guarantee on its own: this is an Alfe chat
|
|
803
|
+
* agent, not a coding session.
|
|
804
|
+
*/
|
|
805
|
+
const PERSONA_POINTER_SYSTEM_PROMPT = [
|
|
806
|
+
"You are an Alfe agent replying to a user over a chat bridge — NOT an interactive coding session.",
|
|
807
|
+
"Your identity, persona, voice, and operating instructions live in CLAUDE.md and the other files in your workspace.",
|
|
808
|
+
"Fully embody that persona in how you speak and act; respond AS that agent, not as a generic coding assistant."
|
|
809
|
+
].join("\n");
|
|
797
810
|
/**
|
|
798
811
|
* One FIFO backlog PER claude-session key. Unlike openclaw-chat's single
|
|
799
812
|
* per-daemon queue, the Claude Code host spawns a distinct `claude -p` per
|
|
@@ -982,7 +995,7 @@ var ClaudeCodeHost = class {
|
|
|
982
995
|
} catch (err) {
|
|
983
996
|
this.log.warn(`[claude-host] memoryLoadContext failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`);
|
|
984
997
|
}
|
|
985
|
-
const appendSystemPrompt =
|
|
998
|
+
const appendSystemPrompt = this.buildSystemPrompt(memoryContext, isVoice);
|
|
986
999
|
const claudeSessionId = this.claudeSessionIds.get(bareSessionId) ?? null;
|
|
987
1000
|
const driver = this.makeDriver();
|
|
988
1001
|
this.runningTurns.set(sessionKey, req.id);
|
|
@@ -995,6 +1008,7 @@ var ClaudeCodeHost = class {
|
|
|
995
1008
|
cwd: this.cfg.workspace,
|
|
996
1009
|
...this.cfg.mcpConfigPath ? { mcpConfigPath: this.cfg.mcpConfigPath } : {},
|
|
997
1010
|
...appendSystemPrompt ? { appendSystemPrompt } : {},
|
|
1011
|
+
...this.cfg.model ? { model: this.cfg.model } : {},
|
|
998
1012
|
onEmission: (emission) => {
|
|
999
1013
|
this.forwardEmission(runId, sessionKey, emission);
|
|
1000
1014
|
}
|
|
@@ -1105,7 +1119,11 @@ var ClaudeCodeHost = class {
|
|
|
1105
1119
|
}
|
|
1106
1120
|
async handleSessionsList(req) {
|
|
1107
1121
|
const params = req.params;
|
|
1108
|
-
const sessions = await listSessions(
|
|
1122
|
+
const sessions = await listSessions({
|
|
1123
|
+
channel: params.channel,
|
|
1124
|
+
tenantId: params.tenantId,
|
|
1125
|
+
userId: params.userId
|
|
1126
|
+
});
|
|
1109
1127
|
this.chat.sendResponse(req.id, true, { sessions });
|
|
1110
1128
|
}
|
|
1111
1129
|
async handleSessionsGet(req) {
|
|
@@ -1139,23 +1157,13 @@ var ClaudeCodeHost = class {
|
|
|
1139
1157
|
activity: session.activity ?? []
|
|
1140
1158
|
});
|
|
1141
1159
|
}
|
|
1142
|
-
|
|
1143
|
-
const parts = [];
|
|
1144
|
-
const persona = await this.readPersona();
|
|
1145
|
-
if (persona) parts.push(persona);
|
|
1160
|
+
buildSystemPrompt(memoryContext, isVoice) {
|
|
1161
|
+
const parts = [PERSONA_POINTER_SYSTEM_PROMPT];
|
|
1146
1162
|
if (memoryContext) parts.push(`# Relevant memory\n\n${memoryContext}`);
|
|
1147
1163
|
if (isVoice) parts.push(VOICE_REPLY_SYSTEM_PROMPT);
|
|
1148
1164
|
parts.push(CROSS_AGENT_TOOLS_SYSTEM_PROMPT);
|
|
1149
1165
|
return parts.join("\n\n");
|
|
1150
1166
|
}
|
|
1151
|
-
async readPersona() {
|
|
1152
|
-
const chunks = [];
|
|
1153
|
-
for (const file of PERSONA_FILES) try {
|
|
1154
|
-
const text = await readFile(join(this.cfg.workspace, file), "utf-8");
|
|
1155
|
-
if (text.trim()) chunks.push(text.trim());
|
|
1156
|
-
} catch {}
|
|
1157
|
-
return chunks.join("\n\n");
|
|
1158
|
-
}
|
|
1159
1167
|
async buildHistoryPreamble(bareSessionId) {
|
|
1160
1168
|
const session = await getSession(bareSessionId);
|
|
1161
1169
|
if (!session || session.messages.length === 0) return "";
|
|
@@ -1165,7 +1173,7 @@ var ClaudeCodeHost = class {
|
|
|
1165
1173
|
}
|
|
1166
1174
|
async ensureSession(bareSessionId, params) {
|
|
1167
1175
|
if (await getSession(bareSessionId)) return;
|
|
1168
|
-
await createSession(bareSessionId, params.agentId, params.clientType ?? "chat", params.tenantId, params.
|
|
1176
|
+
await createSession(bareSessionId, params.agentId, params.clientType ?? "chat", params.tenantId, params.userId);
|
|
1169
1177
|
}
|
|
1170
1178
|
async loadClaudeSessionIds() {
|
|
1171
1179
|
try {
|
|
@@ -1217,7 +1225,8 @@ function resolveHostConfig() {
|
|
|
1217
1225
|
apiUrl: resolved.apiUrl,
|
|
1218
1226
|
workspace: resolved.workspacePath,
|
|
1219
1227
|
mcpConfigPath: join(homedir(), ".claude-code", "mcp-config.json"),
|
|
1220
|
-
claudeSessionsPath: join(homedir(), ".alfe", "claude-code", "sessions.json")
|
|
1228
|
+
claudeSessionsPath: join(homedir(), ".alfe", "claude-code", "sessions.json"),
|
|
1229
|
+
...process.env.ALFE_DEFAULT_MODEL?.trim() ? { model: process.env.ALFE_DEFAULT_MODEL.trim() } : {}
|
|
1221
1230
|
};
|
|
1222
1231
|
}
|
|
1223
1232
|
//#endregion
|
package/dist/index.d.cts
CHANGED
|
@@ -521,6 +521,67 @@ declare class AgentApiClient {
|
|
|
521
521
|
scopes: string;
|
|
522
522
|
}[];
|
|
523
523
|
}>;
|
|
524
|
+
/**
|
|
525
|
+
* Pattern A: provider-parameterized multi-account credential fetch for the
|
|
526
|
+
* social connectors (Bluesky, and the approval-gated backlog: X, Meta,
|
|
527
|
+
* Threads, LinkedIn, Pinterest, TikTok, Reddit, YouTube).
|
|
528
|
+
*
|
|
529
|
+
* Unlike the bespoke `getGithubAccounts()` / `getXeroAccounts()` shapes,
|
|
530
|
+
* this returns a UNIFORM normalized account shape so `@alfe.ai/social-mcp`'s
|
|
531
|
+
* shared driver can require a single `account` selector on every
|
|
532
|
+
* credential-touching tool regardless of platform. The backend
|
|
533
|
+
* `api-agents/{provider}/accounts` route is already provider-generic; this
|
|
534
|
+
* is the client-side normalization the plan (`do-we-need-any-moonlit-toucan`
|
|
535
|
+
* Phase 0, step 5) calls for.
|
|
536
|
+
*
|
|
537
|
+
* `accountIdentifier` is the stable per-account selector the LLM should
|
|
538
|
+
* pass back (for Bluesky: the account DID). `accessToken` carries whatever
|
|
539
|
+
* the provider's `buildCredentialsResponse` bundles (for Bluesky: the JSON
|
|
540
|
+
* session bundle — the driver parses the `accessJwt` out of it, or reads the
|
|
541
|
+
* top-level `accessJwt` from `providerMetadata`-adjacent fields). Everything
|
|
542
|
+
* else the driver needs for routing (handle, pdsHost, did, …) is on
|
|
543
|
+
* `providerMetadata`.
|
|
544
|
+
*
|
|
545
|
+
* Token refresh is delegated to connect (never done in-plugin) via the
|
|
546
|
+
* per-account route `POST /agent/connect/{provider}/accounts/{accountIdentifier}/refresh`
|
|
547
|
+
* — call `refreshSocialAccount(provider, accountIdentifier)`. (The non-account
|
|
548
|
+
* `POST /agent/connect/{provider}/refresh` route refreshes the provider's
|
|
549
|
+
* PRIMARY connection, which is wrong under multi-account Pattern A.)
|
|
550
|
+
*/
|
|
551
|
+
getSocialAccounts(provider: string): Promise<{
|
|
552
|
+
provider: string;
|
|
553
|
+
accounts: {
|
|
554
|
+
connectionId: string;
|
|
555
|
+
accountIdentifier: string;
|
|
556
|
+
displayName: string | null;
|
|
557
|
+
accessToken: string;
|
|
558
|
+
providerMetadata: Record<string, unknown>;
|
|
559
|
+
connectedAt: string;
|
|
560
|
+
}[];
|
|
561
|
+
}>;
|
|
562
|
+
/**
|
|
563
|
+
* Pattern A: refresh a specific social Connection by its stable
|
|
564
|
+
* `accountIdentifier` (for Bluesky: the account DID) via the
|
|
565
|
+
* provider-generic per-account refresh route. The counterpart to
|
|
566
|
+
* `getSocialAccounts(provider)`; `@alfe.ai/social-mcp` calls this on a
|
|
567
|
+
* 401/ExpiredToken from the platform PDS/API, then re-fetches accounts to
|
|
568
|
+
* pick up the rotated bundle.
|
|
569
|
+
*
|
|
570
|
+
* Refresh itself is ALWAYS delegated to connect — the plugin never calls
|
|
571
|
+
* the platform's own refresh XRPC (e.g. `com.atproto.server.refreshSession`)
|
|
572
|
+
* because connect owns the encrypted refresh token + rotation persistence
|
|
573
|
+
* (Bluesky rotates the refreshJwt; a missed rotation kills the connection
|
|
574
|
+
* after one refresh). The returned `accessToken` is whatever the provider's
|
|
575
|
+
* `refreshToken` hook re-bundled (for Bluesky: the JSON session bundle with
|
|
576
|
+
* the fresh `accessJwt`) — callers typically ignore it and re-fetch via
|
|
577
|
+
* `getSocialAccounts` for a consistent shape.
|
|
578
|
+
*/
|
|
579
|
+
refreshSocialAccount(provider: string, accountIdentifier: string): Promise<{
|
|
580
|
+
accountIdentifier: string;
|
|
581
|
+
accessToken: string;
|
|
582
|
+
accessTokenExpiresAt: string;
|
|
583
|
+
expiresAt: string;
|
|
584
|
+
}>;
|
|
524
585
|
/**
|
|
525
586
|
* @deprecated Returns a single primary credential blob (legacy "pick-the-
|
|
526
587
|
* default-connection" shape). Use `getXeroAccounts()` for the multi-
|
|
@@ -756,6 +817,45 @@ declare class AgentApiClient {
|
|
|
756
817
|
accessTokenExpiresAt: string;
|
|
757
818
|
expiresAt: string;
|
|
758
819
|
}>;
|
|
820
|
+
/**
|
|
821
|
+
* @deprecated Returns a single primary credential blob. Use
|
|
822
|
+
* `getShopifyAccounts()` for the multi-account shape required by Pattern A
|
|
823
|
+
* (`@alfe.ai/shopify-mcp` keys per-shop on the myshopify domain).
|
|
824
|
+
*/
|
|
825
|
+
getShopifyCredentials(): Promise<{
|
|
826
|
+
accessToken: string;
|
|
827
|
+
shopDomain: string;
|
|
828
|
+
shopGid: string;
|
|
829
|
+
shopName: string;
|
|
830
|
+
apiVersion: string;
|
|
831
|
+
}>;
|
|
832
|
+
/**
|
|
833
|
+
* Pattern A: multi-account credential fetch for Shopify. Returns every
|
|
834
|
+
* agent-scoped Shopify Connection. One OAuth grant maps to one store, so the
|
|
835
|
+
* stable per-call selector is the store's myshopify domain (`shopDomain`),
|
|
836
|
+
* NOT `accountIdentifier` — the connect provider keys `accountIdentifier` on
|
|
837
|
+
* the immutable shop GID (falling back to the domain), so `shopDomain` is the
|
|
838
|
+
* value the LLM passes and the plugin routes on.
|
|
839
|
+
*
|
|
840
|
+
* Each entry is shaped by the connect provider's `buildCredentialsResponse`:
|
|
841
|
+
* `{ accessToken, shopDomain, shopGid, shopName, apiVersion }` — offline
|
|
842
|
+
* Shopify tokens never expire, so there is NO token / expiry field and no
|
|
843
|
+
* refresh method (unlike Salesforce). The GraphQL Admin API authenticates
|
|
844
|
+
* purely on `X-Shopify-Access-Token`; no client credentials are on the wire.
|
|
845
|
+
*/
|
|
846
|
+
getShopifyAccounts(): Promise<{
|
|
847
|
+
accounts: {
|
|
848
|
+
connectionId: string;
|
|
849
|
+
accountIdentifier: string;
|
|
850
|
+
displayName: string | null;
|
|
851
|
+
connectedAt: string;
|
|
852
|
+
accessToken: string;
|
|
853
|
+
shopDomain: string;
|
|
854
|
+
shopGid: string;
|
|
855
|
+
shopName: string;
|
|
856
|
+
apiVersion: string;
|
|
857
|
+
}[];
|
|
858
|
+
}>;
|
|
759
859
|
/**
|
|
760
860
|
* Disconnects one connected Microsoft 365 account for the agent, by its
|
|
761
861
|
* `accountIdentifier`. Hits the generic per-account disconnect route
|
|
@@ -1770,6 +1870,8 @@ interface RunTurnParams {
|
|
|
1770
1870
|
mcpConfigPath?: string;
|
|
1771
1871
|
/** Persona + reply-style text appended to the system prompt. Omitted → none. */
|
|
1772
1872
|
appendSystemPrompt?: string;
|
|
1873
|
+
/** Bare Claude model id for `--model` (subscription models only). Omitted → CLI default. */
|
|
1874
|
+
model?: string;
|
|
1773
1875
|
/** Tool allow-list (defaults to DEFAULT_ALLOWED_TOOLS). */
|
|
1774
1876
|
allowedTools?: readonly string[];
|
|
1775
1877
|
/** Permission mode (defaults to DEFAULT_PERMISSION_MODE — never bypass). */
|
|
@@ -1838,6 +1940,13 @@ interface ClaudeCodeHostConfig {
|
|
|
1838
1940
|
mcpConfigPath?: string;
|
|
1839
1941
|
/** Path to persist Alfe sessionId → claude session id. */
|
|
1840
1942
|
claudeSessionsPath?: string;
|
|
1943
|
+
/**
|
|
1944
|
+
* Bare Claude model id for `claude -p --model` (e.g. `claude-opus-4-8` or the
|
|
1945
|
+
* `opus`/`sonnet`/`haiku` aliases). Sourced from the agent's `defaultModel`
|
|
1946
|
+
* via `ALFE_DEFAULT_MODEL`. Omitted → the operator's `claude` CLI default.
|
|
1947
|
+
* NEVER provider-qualified (`anthropic/…`) — that's an OpenClaw-only shape.
|
|
1948
|
+
*/
|
|
1949
|
+
model?: string;
|
|
1841
1950
|
logger?: Logger;
|
|
1842
1951
|
}
|
|
1843
1952
|
declare class ClaudeCodeHost {
|
|
@@ -1889,7 +1998,6 @@ declare class ClaudeCodeHost {
|
|
|
1889
1998
|
private handleSessionsList;
|
|
1890
1999
|
private handleSessionsGet;
|
|
1891
2000
|
private buildSystemPrompt;
|
|
1892
|
-
private readPersona;
|
|
1893
2001
|
private buildHistoryPreamble;
|
|
1894
2002
|
private ensureSession;
|
|
1895
2003
|
private loadClaudeSessionIds;
|
package/dist/index.d.ts
CHANGED
|
@@ -521,6 +521,67 @@ declare class AgentApiClient {
|
|
|
521
521
|
scopes: string;
|
|
522
522
|
}[];
|
|
523
523
|
}>;
|
|
524
|
+
/**
|
|
525
|
+
* Pattern A: provider-parameterized multi-account credential fetch for the
|
|
526
|
+
* social connectors (Bluesky, and the approval-gated backlog: X, Meta,
|
|
527
|
+
* Threads, LinkedIn, Pinterest, TikTok, Reddit, YouTube).
|
|
528
|
+
*
|
|
529
|
+
* Unlike the bespoke `getGithubAccounts()` / `getXeroAccounts()` shapes,
|
|
530
|
+
* this returns a UNIFORM normalized account shape so `@alfe.ai/social-mcp`'s
|
|
531
|
+
* shared driver can require a single `account` selector on every
|
|
532
|
+
* credential-touching tool regardless of platform. The backend
|
|
533
|
+
* `api-agents/{provider}/accounts` route is already provider-generic; this
|
|
534
|
+
* is the client-side normalization the plan (`do-we-need-any-moonlit-toucan`
|
|
535
|
+
* Phase 0, step 5) calls for.
|
|
536
|
+
*
|
|
537
|
+
* `accountIdentifier` is the stable per-account selector the LLM should
|
|
538
|
+
* pass back (for Bluesky: the account DID). `accessToken` carries whatever
|
|
539
|
+
* the provider's `buildCredentialsResponse` bundles (for Bluesky: the JSON
|
|
540
|
+
* session bundle — the driver parses the `accessJwt` out of it, or reads the
|
|
541
|
+
* top-level `accessJwt` from `providerMetadata`-adjacent fields). Everything
|
|
542
|
+
* else the driver needs for routing (handle, pdsHost, did, …) is on
|
|
543
|
+
* `providerMetadata`.
|
|
544
|
+
*
|
|
545
|
+
* Token refresh is delegated to connect (never done in-plugin) via the
|
|
546
|
+
* per-account route `POST /agent/connect/{provider}/accounts/{accountIdentifier}/refresh`
|
|
547
|
+
* — call `refreshSocialAccount(provider, accountIdentifier)`. (The non-account
|
|
548
|
+
* `POST /agent/connect/{provider}/refresh` route refreshes the provider's
|
|
549
|
+
* PRIMARY connection, which is wrong under multi-account Pattern A.)
|
|
550
|
+
*/
|
|
551
|
+
getSocialAccounts(provider: string): Promise<{
|
|
552
|
+
provider: string;
|
|
553
|
+
accounts: {
|
|
554
|
+
connectionId: string;
|
|
555
|
+
accountIdentifier: string;
|
|
556
|
+
displayName: string | null;
|
|
557
|
+
accessToken: string;
|
|
558
|
+
providerMetadata: Record<string, unknown>;
|
|
559
|
+
connectedAt: string;
|
|
560
|
+
}[];
|
|
561
|
+
}>;
|
|
562
|
+
/**
|
|
563
|
+
* Pattern A: refresh a specific social Connection by its stable
|
|
564
|
+
* `accountIdentifier` (for Bluesky: the account DID) via the
|
|
565
|
+
* provider-generic per-account refresh route. The counterpart to
|
|
566
|
+
* `getSocialAccounts(provider)`; `@alfe.ai/social-mcp` calls this on a
|
|
567
|
+
* 401/ExpiredToken from the platform PDS/API, then re-fetches accounts to
|
|
568
|
+
* pick up the rotated bundle.
|
|
569
|
+
*
|
|
570
|
+
* Refresh itself is ALWAYS delegated to connect — the plugin never calls
|
|
571
|
+
* the platform's own refresh XRPC (e.g. `com.atproto.server.refreshSession`)
|
|
572
|
+
* because connect owns the encrypted refresh token + rotation persistence
|
|
573
|
+
* (Bluesky rotates the refreshJwt; a missed rotation kills the connection
|
|
574
|
+
* after one refresh). The returned `accessToken` is whatever the provider's
|
|
575
|
+
* `refreshToken` hook re-bundled (for Bluesky: the JSON session bundle with
|
|
576
|
+
* the fresh `accessJwt`) — callers typically ignore it and re-fetch via
|
|
577
|
+
* `getSocialAccounts` for a consistent shape.
|
|
578
|
+
*/
|
|
579
|
+
refreshSocialAccount(provider: string, accountIdentifier: string): Promise<{
|
|
580
|
+
accountIdentifier: string;
|
|
581
|
+
accessToken: string;
|
|
582
|
+
accessTokenExpiresAt: string;
|
|
583
|
+
expiresAt: string;
|
|
584
|
+
}>;
|
|
524
585
|
/**
|
|
525
586
|
* @deprecated Returns a single primary credential blob (legacy "pick-the-
|
|
526
587
|
* default-connection" shape). Use `getXeroAccounts()` for the multi-
|
|
@@ -756,6 +817,45 @@ declare class AgentApiClient {
|
|
|
756
817
|
accessTokenExpiresAt: string;
|
|
757
818
|
expiresAt: string;
|
|
758
819
|
}>;
|
|
820
|
+
/**
|
|
821
|
+
* @deprecated Returns a single primary credential blob. Use
|
|
822
|
+
* `getShopifyAccounts()` for the multi-account shape required by Pattern A
|
|
823
|
+
* (`@alfe.ai/shopify-mcp` keys per-shop on the myshopify domain).
|
|
824
|
+
*/
|
|
825
|
+
getShopifyCredentials(): Promise<{
|
|
826
|
+
accessToken: string;
|
|
827
|
+
shopDomain: string;
|
|
828
|
+
shopGid: string;
|
|
829
|
+
shopName: string;
|
|
830
|
+
apiVersion: string;
|
|
831
|
+
}>;
|
|
832
|
+
/**
|
|
833
|
+
* Pattern A: multi-account credential fetch for Shopify. Returns every
|
|
834
|
+
* agent-scoped Shopify Connection. One OAuth grant maps to one store, so the
|
|
835
|
+
* stable per-call selector is the store's myshopify domain (`shopDomain`),
|
|
836
|
+
* NOT `accountIdentifier` — the connect provider keys `accountIdentifier` on
|
|
837
|
+
* the immutable shop GID (falling back to the domain), so `shopDomain` is the
|
|
838
|
+
* value the LLM passes and the plugin routes on.
|
|
839
|
+
*
|
|
840
|
+
* Each entry is shaped by the connect provider's `buildCredentialsResponse`:
|
|
841
|
+
* `{ accessToken, shopDomain, shopGid, shopName, apiVersion }` — offline
|
|
842
|
+
* Shopify tokens never expire, so there is NO token / expiry field and no
|
|
843
|
+
* refresh method (unlike Salesforce). The GraphQL Admin API authenticates
|
|
844
|
+
* purely on `X-Shopify-Access-Token`; no client credentials are on the wire.
|
|
845
|
+
*/
|
|
846
|
+
getShopifyAccounts(): Promise<{
|
|
847
|
+
accounts: {
|
|
848
|
+
connectionId: string;
|
|
849
|
+
accountIdentifier: string;
|
|
850
|
+
displayName: string | null;
|
|
851
|
+
connectedAt: string;
|
|
852
|
+
accessToken: string;
|
|
853
|
+
shopDomain: string;
|
|
854
|
+
shopGid: string;
|
|
855
|
+
shopName: string;
|
|
856
|
+
apiVersion: string;
|
|
857
|
+
}[];
|
|
858
|
+
}>;
|
|
759
859
|
/**
|
|
760
860
|
* Disconnects one connected Microsoft 365 account for the agent, by its
|
|
761
861
|
* `accountIdentifier`. Hits the generic per-account disconnect route
|
|
@@ -1770,6 +1870,8 @@ interface RunTurnParams {
|
|
|
1770
1870
|
mcpConfigPath?: string;
|
|
1771
1871
|
/** Persona + reply-style text appended to the system prompt. Omitted → none. */
|
|
1772
1872
|
appendSystemPrompt?: string;
|
|
1873
|
+
/** Bare Claude model id for `--model` (subscription models only). Omitted → CLI default. */
|
|
1874
|
+
model?: string;
|
|
1773
1875
|
/** Tool allow-list (defaults to DEFAULT_ALLOWED_TOOLS). */
|
|
1774
1876
|
allowedTools?: readonly string[];
|
|
1775
1877
|
/** Permission mode (defaults to DEFAULT_PERMISSION_MODE — never bypass). */
|
|
@@ -1838,6 +1940,13 @@ interface ClaudeCodeHostConfig {
|
|
|
1838
1940
|
mcpConfigPath?: string;
|
|
1839
1941
|
/** Path to persist Alfe sessionId → claude session id. */
|
|
1840
1942
|
claudeSessionsPath?: string;
|
|
1943
|
+
/**
|
|
1944
|
+
* Bare Claude model id for `claude -p --model` (e.g. `claude-opus-4-8` or the
|
|
1945
|
+
* `opus`/`sonnet`/`haiku` aliases). Sourced from the agent's `defaultModel`
|
|
1946
|
+
* via `ALFE_DEFAULT_MODEL`. Omitted → the operator's `claude` CLI default.
|
|
1947
|
+
* NEVER provider-qualified (`anthropic/…`) — that's an OpenClaw-only shape.
|
|
1948
|
+
*/
|
|
1949
|
+
model?: string;
|
|
1841
1950
|
logger?: Logger;
|
|
1842
1951
|
}
|
|
1843
1952
|
declare class ClaudeCodeHost {
|
|
@@ -1889,7 +1998,6 @@ declare class ClaudeCodeHost {
|
|
|
1889
1998
|
private handleSessionsList;
|
|
1890
1999
|
private handleSessionsGet;
|
|
1891
2000
|
private buildSystemPrompt;
|
|
1892
|
-
private readPersona;
|
|
1893
2001
|
private buildHistoryPreamble;
|
|
1894
2002
|
private ensureSession;
|
|
1895
2003
|
private loadClaudeSessionIds;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alfe.ai/claude-code-host",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Chat bridge that makes a self-hosted Claude Code agent reachable from Alfe chat on the user's Claude subscription",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"dist"
|
|
20
20
|
],
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@alfe.ai/agent-api-client": "^0.
|
|
22
|
+
"@alfe.ai/agent-api-client": "^0.12.0",
|
|
23
23
|
"@alfe.ai/chat": "^0.0.16",
|
|
24
24
|
"@alfe.ai/config": "^0.3.0"
|
|
25
25
|
},
|