@1presence/bridge 0.14.0 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/claude.js +1 -1
- package/dist/config.js +24 -59
- package/dist/index.js +23 -7
- package/package.json +1 -1
package/dist/claude.js
CHANGED
|
@@ -227,7 +227,7 @@ function spawnClaude(params) {
|
|
|
227
227
|
// First conversation since bridge started — announce prominently
|
|
228
228
|
// so the user can confirm which model and credential is in use.
|
|
229
229
|
const source = keySource === 'none' || !keySource ? 'claude.ai subscription' : keySource;
|
|
230
|
-
const pin = (0, config_1.getBridgeModel)() ? ' (
|
|
230
|
+
const pin = (0, config_1.getBridgeModel)() ? ' (selected at startup)' : '';
|
|
231
231
|
process.stdout.write(`\n model: ${model ?? 'unknown'}${pin}\n auth: ${source}\n\n`);
|
|
232
232
|
modelAnnounced = true;
|
|
233
233
|
}
|
package/dist/config.js
CHANGED
|
@@ -2,35 +2,16 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ensureModelChoice = ensureModelChoice;
|
|
4
4
|
exports.getBridgeModel = getBridgeModel;
|
|
5
|
-
const fs_1 = require("fs");
|
|
6
|
-
const os_1 = require("os");
|
|
7
|
-
const path_1 = require("path");
|
|
8
5
|
const readline_1 = require("readline");
|
|
9
6
|
const child_process_1 = require("child_process");
|
|
10
|
-
// ───
|
|
7
|
+
// ─── In-memory model choice ───────────────────────────────────────────────────
|
|
11
8
|
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
let
|
|
17
|
-
|
|
18
|
-
if (cached)
|
|
19
|
-
return cached;
|
|
20
|
-
try {
|
|
21
|
-
cached = JSON.parse((0, fs_1.readFileSync)(CONFIG_FILE, 'utf-8'));
|
|
22
|
-
}
|
|
23
|
-
catch {
|
|
24
|
-
cached = {};
|
|
25
|
-
}
|
|
26
|
-
return cached;
|
|
27
|
-
}
|
|
28
|
-
function persist(c) {
|
|
29
|
-
(0, fs_1.mkdirSync)(CONFIG_DIR, { recursive: true });
|
|
30
|
-
(0, fs_1.writeFileSync)(CONFIG_FILE, JSON.stringify(c, null, 2), 'utf-8');
|
|
31
|
-
cached = c;
|
|
32
|
-
}
|
|
33
|
-
// ─── Model choice ─────────────────────────────────────────────────────────────
|
|
9
|
+
// The bridge prompts for a model on every interactive startup. The choice is
|
|
10
|
+
// kept in memory for the life of the process — nothing is written to disk.
|
|
11
|
+
// In a non-TTY environment the prompt is skipped and Claude Code's own default
|
|
12
|
+
// is used.
|
|
13
|
+
let selectedModel = null;
|
|
14
|
+
// ─── Default-model probe ──────────────────────────────────────────────────────
|
|
34
15
|
/**
|
|
35
16
|
* Asks the local `claude` CLI which model it would pick by default, by reading
|
|
36
17
|
* the `model` field of the `system/init` stream-json event and killing the
|
|
@@ -106,27 +87,18 @@ const MODEL_OPTIONS = [
|
|
|
106
87
|
{ num: 4, model: 'claude-haiku-4-5', label: 'claude-haiku-4-5' },
|
|
107
88
|
];
|
|
108
89
|
const PROMPT_TIMEOUT_MS = 10_000;
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const match = MODEL_OPTIONS.find((o) => o.model === previous);
|
|
112
|
-
if (match)
|
|
113
|
-
return match.num;
|
|
114
|
-
}
|
|
115
|
-
// Either never asked (undefined) or explicit no-override (null) → option 1.
|
|
116
|
-
return 1;
|
|
117
|
-
}
|
|
118
|
-
function promptForModel(defaultModel, previousChoice) {
|
|
90
|
+
const DEFAULT_OPTION_NUM = 1;
|
|
91
|
+
function promptForModel(defaultModel) {
|
|
119
92
|
return new Promise((resolve) => {
|
|
120
93
|
const rl = (0, readline_1.createInterface)({ input: process.stdin, output: process.stdout });
|
|
121
|
-
const defaultNum = defaultOptionNum(previousChoice);
|
|
122
94
|
process.stdout.write('\nWhich Claude model should the bridge use?\n');
|
|
123
95
|
for (const opt of MODEL_OPTIONS) {
|
|
124
|
-
const isDefault = opt.num ===
|
|
96
|
+
const isDefault = opt.num === DEFAULT_OPTION_NUM;
|
|
125
97
|
const marker = isDefault ? '*' : ' ';
|
|
126
98
|
const suffix = opt.num === 1 && defaultModel ? ` (${defaultModel})` : '';
|
|
127
99
|
process.stdout.write(` ${marker} ${opt.num}) ${opt.label}${suffix}\n`);
|
|
128
100
|
}
|
|
129
|
-
process.stdout.write(` (* =
|
|
101
|
+
process.stdout.write(` (* = default; auto-selected in ${PROMPT_TIMEOUT_MS / 1000}s if nothing pressed)\n`);
|
|
130
102
|
let settled = false;
|
|
131
103
|
const finish = (model) => {
|
|
132
104
|
if (settled)
|
|
@@ -137,14 +109,14 @@ function promptForModel(defaultModel, previousChoice) {
|
|
|
137
109
|
resolve(model);
|
|
138
110
|
};
|
|
139
111
|
const timer = setTimeout(() => {
|
|
140
|
-
const def = MODEL_OPTIONS.find((o) => o.num ===
|
|
141
|
-
process.stdout.write(`\n(timed out — using option ${
|
|
112
|
+
const def = MODEL_OPTIONS.find((o) => o.num === DEFAULT_OPTION_NUM);
|
|
113
|
+
process.stdout.write(`\n(timed out — using option ${DEFAULT_OPTION_NUM})\n`);
|
|
142
114
|
finish(def.model);
|
|
143
115
|
}, PROMPT_TIMEOUT_MS);
|
|
144
116
|
rl.question(' choice: ', (answer) => {
|
|
145
117
|
const trimmed = answer.trim();
|
|
146
118
|
if (!trimmed) {
|
|
147
|
-
const def = MODEL_OPTIONS.find((o) => o.num ===
|
|
119
|
+
const def = MODEL_OPTIONS.find((o) => o.num === DEFAULT_OPTION_NUM);
|
|
148
120
|
finish(def.model);
|
|
149
121
|
return;
|
|
150
122
|
}
|
|
@@ -160,32 +132,25 @@ function promptForModel(defaultModel, previousChoice) {
|
|
|
160
132
|
});
|
|
161
133
|
}
|
|
162
134
|
/**
|
|
163
|
-
* Asks the user which model to
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
* the prompt is skipped: an existing pin is kept, and a first non-TTY start
|
|
167
|
-
* records "no override" so we don't keep trying.
|
|
135
|
+
* Asks the user which model to use for this bridge session. The choice lives
|
|
136
|
+
* in memory only — every startup re-prompts. In a non-TTY environment the
|
|
137
|
+
* prompt is skipped and Claude Code's own default is used.
|
|
168
138
|
*/
|
|
169
139
|
async function ensureModelChoice() {
|
|
170
|
-
const c = load();
|
|
171
140
|
if (!process.stdin.isTTY) {
|
|
172
|
-
|
|
173
|
-
persist({ ...c, model: null });
|
|
141
|
+
selectedModel = null;
|
|
174
142
|
return;
|
|
175
143
|
}
|
|
176
144
|
const defaultModel = await detectClaudeDefaultModel();
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
console.log(`\nPinned model: ${chosen}`);
|
|
181
|
-
console.log(`(Edit or delete ~/.1presence/config.json to change.)\n`);
|
|
145
|
+
selectedModel = await promptForModel(defaultModel);
|
|
146
|
+
if (selectedModel) {
|
|
147
|
+
console.log(`\nUsing model: ${selectedModel} (this session only)\n`);
|
|
182
148
|
}
|
|
183
149
|
else {
|
|
184
|
-
console.log(`\nUsing your Claude Code default${defaultModel ? ` (${defaultModel})` : ''}
|
|
185
|
-
console.log(`(Edit ~/.1presence/config.json to pin a model later.)\n`);
|
|
150
|
+
console.log(`\nUsing your Claude Code default${defaultModel ? ` (${defaultModel})` : ''}.\n`);
|
|
186
151
|
}
|
|
187
152
|
}
|
|
188
|
-
/** Returns the
|
|
153
|
+
/** Returns the model id chosen for this session, or null to defer to Claude Code's own default. */
|
|
189
154
|
function getBridgeModel() {
|
|
190
|
-
return
|
|
155
|
+
return selectedModel;
|
|
191
156
|
}
|
package/dist/index.js
CHANGED
|
@@ -75,13 +75,13 @@ async function fetchSystemPrompt(token) {
|
|
|
75
75
|
function tmpFile(name) {
|
|
76
76
|
return (0, path_1.join)((0, os_1.tmpdir)(), name);
|
|
77
77
|
}
|
|
78
|
-
|
|
78
|
+
// Fetch the system prompt and write it to /tmp/agent-${uid}.md. The hosted
|
|
79
|
+
// runtime rebuilds buildSystemBlocks() per turn (dynamic context: vault state,
|
|
80
|
+
// connector status, palace, onboarding phase, skills) — call this per turn in
|
|
81
|
+
// the bridge too, otherwise newly shipped skills and mid-session vault writes
|
|
82
|
+
// never reach a long-running bridge.
|
|
83
|
+
async function writeSystemPrompt(auth) {
|
|
79
84
|
const { uid, token } = auth;
|
|
80
|
-
// Prefer the fully-built hosted system prompt so the bridge runtime behaves
|
|
81
|
-
// identically to the cloud agent (tool-use policy, ui_payload sparsity,
|
|
82
|
-
// plan thresholds, Gmail safety, connector pivots, personal AGENT.md, etc.).
|
|
83
|
-
// If the pod isn't reachable yet, fall back to the user's AGENT.md alone —
|
|
84
|
-
// Claude will still run, just without the platform policy layer.
|
|
85
85
|
const systemPrompt = (await fetchSystemPrompt(token))
|
|
86
86
|
?? (await fetchVaultFile('AGENT.md', token))
|
|
87
87
|
?? (await fetchVaultFile('CLAUDE.md', token))
|
|
@@ -92,7 +92,9 @@ async function writeSetupFiles(auth) {
|
|
|
92
92
|
console.log(systemPrompt);
|
|
93
93
|
console.log('[bridge:verbose] ─── end system prompt ───────────────────\n');
|
|
94
94
|
}
|
|
95
|
-
|
|
95
|
+
}
|
|
96
|
+
function writeMcpConfig(auth) {
|
|
97
|
+
const { uid, token } = auth;
|
|
96
98
|
const mcpConfig = {
|
|
97
99
|
mcpServers: {
|
|
98
100
|
'1presence': {
|
|
@@ -104,6 +106,10 @@ async function writeSetupFiles(auth) {
|
|
|
104
106
|
};
|
|
105
107
|
writeRestricted(tmpFile(`mcp-${uid}.json`), JSON.stringify(mcpConfig, null, 2));
|
|
106
108
|
}
|
|
109
|
+
async function writeSetupFiles(auth) {
|
|
110
|
+
await writeSystemPrompt(auth);
|
|
111
|
+
writeMcpConfig(auth);
|
|
112
|
+
}
|
|
107
113
|
// The MCP config embeds a Bearer JWT and the system prompt may contain vault
|
|
108
114
|
// state. writeFileSync's mode only takes effect on file creation — chmodSync
|
|
109
115
|
// covers the overwrite case so a legacy 0644 file gets tightened on next run.
|
|
@@ -136,6 +142,16 @@ async function handleMessage(conversationId, text, sessionId, auth, vaultFileOpe
|
|
|
136
142
|
}
|
|
137
143
|
console.warn(`[bridge] token refresh failed (proceeding with current token): ${err.message}`);
|
|
138
144
|
}
|
|
145
|
+
// Refresh the system prompt on every turn — the hosted runtime rebuilds its
|
|
146
|
+
// dynamic context per turn (vault state, connector status, palace, onboarding
|
|
147
|
+
// phase, newly enabled skills). Without this the bridge holds a frozen
|
|
148
|
+
// snapshot from process start and misses anything added since.
|
|
149
|
+
try {
|
|
150
|
+
await writeSystemPrompt(activeAuth);
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
console.warn(`[bridge] system prompt refresh failed (using cached): ${err.message}`);
|
|
154
|
+
}
|
|
139
155
|
let responding = false;
|
|
140
156
|
(0, claude_1.spawnClaude)({
|
|
141
157
|
conversationId,
|