codeep 2.20.0 → 2.22.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/acp/server.js +8 -4
- package/dist/api/index.js +26 -19
- package/dist/config/index.d.ts +20 -0
- package/dist/config/index.js +32 -0
- package/dist/renderer/App.js +0 -1
- package/dist/renderer/Input.d.ts +0 -1
- package/dist/renderer/Input.js +0 -1
- package/dist/renderer/commands/registry.js +1 -0
- package/dist/renderer/commands.js +19 -3
- package/dist/renderer/components/Export.js +0 -2
- package/dist/renderer/components/Login.d.ts +0 -1
- package/dist/renderer/components/Login.js +0 -2
- package/dist/renderer/components/Logout.js +0 -2
- package/dist/renderer/components/Settings.d.ts +3 -0
- package/dist/renderer/components/Settings.js +0 -12
- package/dist/renderer/main.js +35 -56
- package/dist/utils/agent.d.ts +7 -0
- package/dist/utils/agent.js +102 -6
- package/dist/utils/auditLog.d.ts +93 -0
- package/dist/utils/auditLog.js +217 -0
- package/dist/utils/codeepCloud.d.ts +30 -4
- package/dist/utils/codeepCloud.js +71 -19
- package/dist/utils/diffPreview.js +0 -1
- package/dist/utils/git.js +0 -1
- package/dist/utils/headlessReview.d.ts +9 -1
- package/dist/utils/headlessReview.js +77 -3
- package/dist/utils/mcpStreamableHttp.d.ts +0 -1
- package/dist/utils/mcpStreamableHttp.js +0 -3
- package/dist/utils/personalities.js +0 -1
- package/dist/utils/reviewFix.d.ts +65 -0
- package/dist/utils/reviewFix.js +141 -0
- package/dist/utils/skillBundles.js +0 -4
- package/dist/utils/smartContext.js +0 -18
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +2 -2
- package/dist/renderer/components/Permission.d.ts +0 -24
- package/dist/renderer/components/Permission.js +0 -113
package/dist/acp/server.js
CHANGED
|
@@ -869,13 +869,17 @@ export function startAcpServer() {
|
|
|
869
869
|
transport.error(msg.id, -32602, `Unknown sessionId: ${params.sessionId}`);
|
|
870
870
|
return;
|
|
871
871
|
}
|
|
872
|
-
const
|
|
873
|
-
|
|
874
|
-
|
|
872
|
+
const { describeSyncFailure } = await import('../utils/codeepCloud.js');
|
|
873
|
+
const sync = await pullPersonalities();
|
|
874
|
+
if (!sync.ok) {
|
|
875
|
+
// The old contract collapsed every failure into one message that also
|
|
876
|
+
// covered "not linked", so a client could not tell an expired session
|
|
877
|
+
// from an unreachable server. Say which.
|
|
878
|
+
transport.error(msg.id, -32001, `Personality sync failed — ${describeSyncFailure(sync.reason)}.`);
|
|
875
879
|
return;
|
|
876
880
|
}
|
|
877
881
|
const list = personalityListResult(params.sessionId);
|
|
878
|
-
const result = { updated, ...list };
|
|
882
|
+
const result = { updated: sync.count, ...list };
|
|
879
883
|
transport.respond(msg.id, result);
|
|
880
884
|
}
|
|
881
885
|
// ── session/prompt ──────────────────────────────────────────────────────────
|
package/dist/api/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as http from 'node:http';
|
|
2
2
|
import * as https from 'node:https';
|
|
3
|
-
import { config, getApiKey, resolveBaseUrl } from '../config/index.js';
|
|
3
|
+
import { config, getApiKey, resolveBaseUrl, describeUnsendableKey } from '../config/index.js';
|
|
4
4
|
import { withRetry, isNetworkError } from '../utils/retry.js';
|
|
5
5
|
import { checkApiRateLimit } from '../utils/ratelimit.js';
|
|
6
6
|
import { getProvider, getProviderBaseUrl, getProviderAuthHeader, usesMaxCompletionTokens, requiresDefaultTemperature, modelRejectsSamplingParams, reasoningParamsFor } from '../config/providers.js';
|
|
@@ -147,6 +147,28 @@ function parseApiError(status, body) {
|
|
|
147
147
|
const truncated = body.length > 200 ? body.slice(0, 200) + '...' : body;
|
|
148
148
|
return `${status} - ${truncated}`;
|
|
149
149
|
}
|
|
150
|
+
/**
|
|
151
|
+
* Put the key in the right header, refusing early if it cannot be sent.
|
|
152
|
+
*
|
|
153
|
+
* `fetch` throws "Cannot convert argument to a ByteString because the character
|
|
154
|
+
* at index N…" for a header value outside Latin-1, counting from the start of
|
|
155
|
+
* `Bearer <key>` — so the index points four characters left of where anyone
|
|
156
|
+
* would look, and the message never mentions the key at all. Worse, the caller
|
|
157
|
+
* treats it as a transient API error and retries twice more, which cannot
|
|
158
|
+
* possibly help.
|
|
159
|
+
*/
|
|
160
|
+
function applyAuthHeader(headers, apiKey, authHeader) {
|
|
161
|
+
const problem = describeUnsendableKey(apiKey);
|
|
162
|
+
if (problem) {
|
|
163
|
+
throw new ApiError(`This API key cannot be used: ${problem}. Re-copy it and run /login to set it again.`, 400);
|
|
164
|
+
}
|
|
165
|
+
if (authHeader === 'Bearer') {
|
|
166
|
+
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
headers['x-api-key'] = apiKey;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
150
172
|
export async function chat(message, history = [], onChunk, onRetry, projectContext, abortSignal) {
|
|
151
173
|
// Update project context if provided
|
|
152
174
|
if (projectContext !== undefined) {
|
|
@@ -377,12 +399,7 @@ async function chatOpenAI(message, history, model, apiKey, onChunk, abortSignal)
|
|
|
377
399
|
const headers = {
|
|
378
400
|
'Content-Type': 'application/json',
|
|
379
401
|
};
|
|
380
|
-
|
|
381
|
-
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
382
|
-
}
|
|
383
|
-
else {
|
|
384
|
-
headers['x-api-key'] = apiKey;
|
|
385
|
-
}
|
|
402
|
+
applyAuthHeader(headers, apiKey, authHeader);
|
|
386
403
|
// OpenRouter: branding headers + opt in to `usage.cost` so the
|
|
387
404
|
// chat path reports authoritative per-call cost just like agentChat
|
|
388
405
|
// does. Kept identical to the agentChat block so the two paths stay
|
|
@@ -650,12 +667,7 @@ async function chatAnthropic(message, history, model, apiKey, onChunk, abortSign
|
|
|
650
667
|
'Content-Type': 'application/json',
|
|
651
668
|
'anthropic-version': '2023-06-01',
|
|
652
669
|
};
|
|
653
|
-
|
|
654
|
-
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
655
|
-
}
|
|
656
|
-
else {
|
|
657
|
-
headers['x-api-key'] = apiKey;
|
|
658
|
-
}
|
|
670
|
+
applyAuthHeader(headers, apiKey, authHeader);
|
|
659
671
|
try {
|
|
660
672
|
// Anthropic prompt caching: wrap system as an array with a
|
|
661
673
|
// `cache_control` marker so the static system prompt (typically large
|
|
@@ -797,12 +809,7 @@ export async function validateApiKey(apiKey, providerId) {
|
|
|
797
809
|
const headers = {
|
|
798
810
|
'Content-Type': 'application/json',
|
|
799
811
|
};
|
|
800
|
-
|
|
801
|
-
headers['Authorization'] = `Bearer ${apiKey}`;
|
|
802
|
-
}
|
|
803
|
-
else {
|
|
804
|
-
headers['x-api-key'] = apiKey;
|
|
805
|
-
}
|
|
812
|
+
applyAuthHeader(headers, apiKey, authHeader);
|
|
806
813
|
if (protocol === 'anthropic') {
|
|
807
814
|
headers['anthropic-version'] = '2023-06-01';
|
|
808
815
|
}
|
package/dist/config/index.d.ts
CHANGED
|
@@ -37,6 +37,12 @@ export interface ConfigSchema {
|
|
|
37
37
|
* user (reply language, style, stack, preferences). Default true; set false
|
|
38
38
|
* to keep the profile files but stop injecting them. Managed via `/me`. */
|
|
39
39
|
userProfile: boolean;
|
|
40
|
+
/** Append a record of what each agent run touched to `.codeep/audit/`.
|
|
41
|
+
* Reads and refusals included — `history.ts` records neither, because it
|
|
42
|
+
* exists to undo writes rather than to say what happened. On unless set
|
|
43
|
+
* false: a record you must remember to enable is not one you can rely on
|
|
44
|
+
* having when you need it. */
|
|
45
|
+
auditLog: boolean;
|
|
40
46
|
/** Auto-learn: at session save, run one LLM pass to extract durable facts /
|
|
41
47
|
* preferences about the user and merge them into `~/.codeep/profile.learned.md`
|
|
42
48
|
* (injected alongside the hand-written profile). OFF by default — opt in via
|
|
@@ -318,3 +324,17 @@ export declare function loadProfile(name: string): Profile | null;
|
|
|
318
324
|
export declare function applyProfile(profile: Profile): void;
|
|
319
325
|
export declare function listProfiles(): string[];
|
|
320
326
|
export declare function deleteProfile(name: string): boolean;
|
|
327
|
+
/**
|
|
328
|
+
* Whether a key can survive being put in an HTTP header.
|
|
329
|
+
*
|
|
330
|
+
* `fetch` encodes header values as Latin-1 and throws "Cannot convert argument
|
|
331
|
+
* to a ByteString" on anything outside it. A key pasted from a web page or a
|
|
332
|
+
* chat message can pick up a non-breaking space, a zero-width character or a
|
|
333
|
+
* curly quote, and the resulting failure names neither the key nor the
|
|
334
|
+
* character — only "the character at index N", counted across the whole header
|
|
335
|
+
* value with `Bearer ` included, which is not where anyone would look.
|
|
336
|
+
*
|
|
337
|
+
* Returns null when the key is fine, or a description that locates the problem
|
|
338
|
+
* without ever reproducing the key itself.
|
|
339
|
+
*/
|
|
340
|
+
export declare function describeUnsendableKey(apiKey: string): string | null;
|
package/dist/config/index.js
CHANGED
|
@@ -175,6 +175,7 @@ function createConfig() {
|
|
|
175
175
|
autoSessionTitle: true,
|
|
176
176
|
autoSummarizeHistory: true,
|
|
177
177
|
userProfile: true,
|
|
178
|
+
auditLog: true,
|
|
178
179
|
autoLearnProfile: false,
|
|
179
180
|
trustedHookProjects: [],
|
|
180
181
|
currentSessionId: '',
|
|
@@ -1264,3 +1265,34 @@ export function deleteProfile(name) {
|
|
|
1264
1265
|
return false;
|
|
1265
1266
|
}
|
|
1266
1267
|
}
|
|
1268
|
+
/**
|
|
1269
|
+
* Whether a key can survive being put in an HTTP header.
|
|
1270
|
+
*
|
|
1271
|
+
* `fetch` encodes header values as Latin-1 and throws "Cannot convert argument
|
|
1272
|
+
* to a ByteString" on anything outside it. A key pasted from a web page or a
|
|
1273
|
+
* chat message can pick up a non-breaking space, a zero-width character or a
|
|
1274
|
+
* curly quote, and the resulting failure names neither the key nor the
|
|
1275
|
+
* character — only "the character at index N", counted across the whole header
|
|
1276
|
+
* value with `Bearer ` included, which is not where anyone would look.
|
|
1277
|
+
*
|
|
1278
|
+
* Returns null when the key is fine, or a description that locates the problem
|
|
1279
|
+
* without ever reproducing the key itself.
|
|
1280
|
+
*/
|
|
1281
|
+
export function describeUnsendableKey(apiKey) {
|
|
1282
|
+
for (let i = 0; i < apiKey.length; i++) {
|
|
1283
|
+
const code = apiKey.charCodeAt(i);
|
|
1284
|
+
if (code > 0xFF) {
|
|
1285
|
+
const name = code === 0x200B ? 'a zero-width space'
|
|
1286
|
+
: code === 0x2018 || code === 0x2019 ? 'a curly quote'
|
|
1287
|
+
: code === 0x201C || code === 0x201D ? 'a curly double quote'
|
|
1288
|
+
: `U+${code.toString(16).toUpperCase().padStart(4, '0')}`;
|
|
1289
|
+
return `character ${i + 1} of the key is ${name}, which cannot be sent in an HTTP header`;
|
|
1290
|
+
}
|
|
1291
|
+
// 0xA0 is inside Latin-1 and technically sendable, but a non-breaking space
|
|
1292
|
+
// in a key is never intentional and produces a 401 that reads as a bad key.
|
|
1293
|
+
if (code === 0xA0) {
|
|
1294
|
+
return `character ${i + 1} of the key is a non-breaking space — probably picked up when copying`;
|
|
1295
|
+
}
|
|
1296
|
+
}
|
|
1297
|
+
return null;
|
|
1298
|
+
}
|
package/dist/renderer/App.js
CHANGED
|
@@ -1393,7 +1393,6 @@ export class App {
|
|
|
1393
1393
|
mentionItemCount: this.mention.items.length,
|
|
1394
1394
|
});
|
|
1395
1395
|
const layout = chatLayout(height, panelHeight);
|
|
1396
|
-
const mainHeight = layout.mainHeight;
|
|
1397
1396
|
const headerHeight = width >= 60 && height >= 16 ? 2 : 0;
|
|
1398
1397
|
const messagesStart = Math.min(layout.messagesEnd, headerHeight);
|
|
1399
1398
|
const messagesEnd = layout.messagesEnd;
|
package/dist/renderer/Input.d.ts
CHANGED
package/dist/renderer/Input.js
CHANGED
|
@@ -205,6 +205,7 @@ export const COMMANDS = [
|
|
|
205
205
|
usage: ['init [project]', 'learn [on|off]', 'sync', 'off', 'forget'],
|
|
206
206
|
},
|
|
207
207
|
{ name: 'agents', description: 'List sub-agents the agent can delegate to (researcher / reviewer / tester / your own)', category: 'settings' },
|
|
208
|
+
{ name: 'audit', description: 'What agents did in this project — runs, tools used, and anything the boundary refused', category: 'settings', usage: ['on', 'off'] },
|
|
208
209
|
{ name: 'insights', description: 'Activity summary — runs, files, tools, projects over the last N days (default 7)', category: 'settings', usage: ['--days N'] },
|
|
209
210
|
{ name: 'openrouter', description: 'OpenRouter routing prefs (prefer/ignore providers, fallbacks, privacy)', category: 'settings' },
|
|
210
211
|
// ── extensions & mcp ───────────────────────────────────────────────────────
|
|
@@ -445,6 +445,23 @@ export async function handleCommand(command, args, ctx) {
|
|
|
445
445
|
});
|
|
446
446
|
break;
|
|
447
447
|
}
|
|
448
|
+
case 'audit': {
|
|
449
|
+
const { formatAuditLog } = await import('../utils/auditLog.js');
|
|
450
|
+
const sub = args[0]?.toLowerCase();
|
|
451
|
+
if (sub === 'on' || sub === 'off') {
|
|
452
|
+
config.set('auditLog', sub === 'on');
|
|
453
|
+
ctx.app.notify(sub === 'on'
|
|
454
|
+
? 'Audit recording on — runs are recorded to .codeep/audit/.'
|
|
455
|
+
: 'Audit recording off. Records already written are kept.');
|
|
456
|
+
break;
|
|
457
|
+
}
|
|
458
|
+
if (sub) {
|
|
459
|
+
ctx.app.notify(`Unknown audit subcommand: ${sub}. Use /audit, /audit on, or /audit off`);
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
462
|
+
ctx.app.addMessage({ role: 'system', content: formatAuditLog(ctx.projectPath) });
|
|
463
|
+
break;
|
|
464
|
+
}
|
|
448
465
|
case 'agents': {
|
|
449
466
|
// List sub-agents the agent can `delegate` to (built-in + .codeep/agents/).
|
|
450
467
|
const { formatAgentList } = await import('../utils/agents.js');
|
|
@@ -2102,7 +2119,6 @@ Describe what this skill does. The agent reads this body verbatim when it invoke
|
|
|
2102
2119
|
}
|
|
2103
2120
|
case 'profile': {
|
|
2104
2121
|
const subCmd = args[0]?.toLowerCase();
|
|
2105
|
-
const profileName = args[1] || args[0]; // /profile save name OR /profile name
|
|
2106
2122
|
if (!subCmd || subCmd === 'list') {
|
|
2107
2123
|
const profiles = listProfiles();
|
|
2108
2124
|
if (profiles.length === 0) {
|
|
@@ -2165,9 +2181,9 @@ Describe what this skill does. The agent reads this body verbatim when it invoke
|
|
|
2165
2181
|
}
|
|
2166
2182
|
case 'sync': {
|
|
2167
2183
|
const subCmd = args[0]?.toLowerCase() || 'all';
|
|
2168
|
-
const { pushLearning,
|
|
2184
|
+
const { pushLearning, pushProfiles, pullProfiles } = await import('../utils/codeepCloud.js');
|
|
2169
2185
|
const { getSyncToken } = await import('../config/index.js');
|
|
2170
|
-
const { loadGlobalPreferences
|
|
2186
|
+
const { loadGlobalPreferences } = await import('../utils/learning.js');
|
|
2171
2187
|
if (!getSyncToken()) {
|
|
2172
2188
|
ctx.app.notify('Not linked to codeep.dev. Run: codeep account');
|
|
2173
2189
|
break;
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
* Export panel component
|
|
3
3
|
*/
|
|
4
4
|
import { fg, style } from '../ansi.js';
|
|
5
|
-
// Primary color: #f02a30 (Codeep red)
|
|
6
|
-
const PRIMARY_COLOR = fg.rgb(240, 42, 48);
|
|
7
5
|
const FORMATS = [
|
|
8
6
|
{ id: 'md', name: 'Markdown', desc: 'Formatted with headers and separators' },
|
|
9
7
|
{ id: 'json', name: 'JSON', desc: 'Structured data format' },
|
|
@@ -14,13 +14,11 @@ const PRIMARY_BRIGHT = fg.rgb(255, 80, 85);
|
|
|
14
14
|
*/
|
|
15
15
|
export class LoginScreen {
|
|
16
16
|
screen;
|
|
17
|
-
input;
|
|
18
17
|
editor;
|
|
19
18
|
options;
|
|
20
19
|
showKey = false;
|
|
21
20
|
constructor(screen, input, options) {
|
|
22
21
|
this.screen = screen;
|
|
23
|
-
this.input = input;
|
|
24
22
|
this.editor = new LineEditor();
|
|
25
23
|
this.options = options;
|
|
26
24
|
}
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Settings screen component
|
|
3
3
|
*/
|
|
4
|
-
import { fg } from '../ansi.js';
|
|
5
4
|
import { config } from '../../config/index.js';
|
|
6
5
|
import { updateRateLimits } from '../../utils/ratelimit.js';
|
|
7
|
-
// Primary color: #f02a30 (Codeep red)
|
|
8
|
-
const PRIMARY_COLOR = fg.rgb(240, 42, 48);
|
|
9
|
-
const PRIMARY_BRIGHT = fg.rgb(255, 80, 85);
|
|
10
6
|
/**
|
|
11
7
|
* Write a value to the config for a given setting.
|
|
12
8
|
*
|
|
@@ -295,14 +291,6 @@ export const SETTINGS = [
|
|
|
295
291
|
/**
|
|
296
292
|
* Format value for display
|
|
297
293
|
*/
|
|
298
|
-
function formatValue(setting) {
|
|
299
|
-
const value = setting.getValue();
|
|
300
|
-
if (setting.type === 'select' && setting.options) {
|
|
301
|
-
const option = setting.options.find(o => o.value === value);
|
|
302
|
-
return option ? option.label : String(value);
|
|
303
|
-
}
|
|
304
|
-
return String(value);
|
|
305
|
-
}
|
|
306
294
|
/**
|
|
307
295
|
* Handle settings key
|
|
308
296
|
* Returns: { handled: boolean, close: boolean, notify?: string }
|
package/dist/renderer/main.js
CHANGED
|
@@ -9,7 +9,6 @@ import { App } from './App.js';
|
|
|
9
9
|
import { Screen } from './Screen.js';
|
|
10
10
|
import { Input } from './Input.js';
|
|
11
11
|
import { LoginScreen, renderProviderSelect } from './components/Login.js';
|
|
12
|
-
import { renderPermissionScreen, getPermissionOptions } from './components/Permission.js';
|
|
13
12
|
import { chat, setProjectContext } from '../api/index.js';
|
|
14
13
|
import { getZaiVisionConfig, getMinimaxMcpConfig, callZaiVisionApi, callMinimaxApi } from '../utils/mcpIntegration.js';
|
|
15
14
|
import { config, loadApiKey, loadAllApiKeys, getCurrentProvider, autoSaveSession, startNewSession, getCurrentSessionId, loadSession, listSessionsWithInfo, deleteSession, hasReadPermission, hasWritePermission, setProjectPermission, initializeAsProject, isManuallyInitializedProject, setApiKey, setProvider, getGithubId, } from '../config/index.js';
|
|
@@ -384,49 +383,6 @@ async function showLoginFlow() {
|
|
|
384
383
|
renderCurrentStep();
|
|
385
384
|
});
|
|
386
385
|
}
|
|
387
|
-
// ─── Permission flow (full-screen, pre-app) ───────────────────────────────────
|
|
388
|
-
async function showPermissionFlow() {
|
|
389
|
-
return new Promise((resolve) => {
|
|
390
|
-
const screen = new Screen();
|
|
391
|
-
const input = new Input();
|
|
392
|
-
let selectedIndex = 0;
|
|
393
|
-
const options = getPermissionOptions();
|
|
394
|
-
const isProject = isProjectDirectory(projectPath);
|
|
395
|
-
const currentPermission = hasWritePermission(projectPath)
|
|
396
|
-
? 'write'
|
|
397
|
-
: hasReadPermission(projectPath)
|
|
398
|
-
? 'read'
|
|
399
|
-
: 'none';
|
|
400
|
-
screen.init();
|
|
401
|
-
input.start();
|
|
402
|
-
const cleanup = () => { input.stop(); screen.cleanup(); };
|
|
403
|
-
const render = () => {
|
|
404
|
-
renderPermissionScreen(screen, {
|
|
405
|
-
projectPath, isProject, currentPermission,
|
|
406
|
-
onSelect: () => { }, onCancel: () => { },
|
|
407
|
-
}, selectedIndex);
|
|
408
|
-
};
|
|
409
|
-
input.onKey((event) => {
|
|
410
|
-
if (event.key === 'up') {
|
|
411
|
-
selectedIndex = Math.max(0, selectedIndex - 1);
|
|
412
|
-
render();
|
|
413
|
-
}
|
|
414
|
-
else if (event.key === 'down') {
|
|
415
|
-
selectedIndex = Math.min(options.length - 1, selectedIndex + 1);
|
|
416
|
-
render();
|
|
417
|
-
}
|
|
418
|
-
else if (event.key === 'enter') {
|
|
419
|
-
cleanup();
|
|
420
|
-
resolve(options[selectedIndex]);
|
|
421
|
-
}
|
|
422
|
-
else if (event.key === 'escape') {
|
|
423
|
-
cleanup();
|
|
424
|
-
resolve('none');
|
|
425
|
-
}
|
|
426
|
-
});
|
|
427
|
-
render();
|
|
428
|
-
});
|
|
429
|
-
}
|
|
430
386
|
// ─── Session picker ───────────────────────────────────────────────────────────
|
|
431
387
|
function showSessionPickerInline() {
|
|
432
388
|
const sessions = listSessionsWithInfo(projectPath);
|
|
@@ -544,16 +500,32 @@ Commands (in chat):
|
|
|
544
500
|
// the user profile. Web-edited personalities replace their local copy
|
|
545
501
|
// after a safety backup; commands/profile retain additive merge rules.
|
|
546
502
|
const { pullPersonalities, pullCommands, pullUserProfile, getLastPersonalityPullBackupCount } = await import('../utils/codeepCloud.js');
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
503
|
+
// Report all three outcomes, not just the interesting one. Printing only
|
|
504
|
+
// on count > 0 made a failed sync look identical to a sync with nothing
|
|
505
|
+
// new — silence meant either, and the user could not tell which.
|
|
506
|
+
const { describeSyncFailure } = await import('../utils/codeepCloud.js');
|
|
507
|
+
const personalities = await pullPersonalities();
|
|
508
|
+
if (!personalities.ok) {
|
|
509
|
+
console.log(` Could not pull agents — ${describeSyncFailure(personalities.reason)}.`);
|
|
510
|
+
}
|
|
511
|
+
else if (personalities.count > 0) {
|
|
512
|
+
console.log(` Pulled ${personalities.count} personalit${personalities.count === 1 ? 'y' : 'ies'}.`);
|
|
550
513
|
const backups = getLastPersonalityPullBackupCount();
|
|
551
514
|
if (backups > 0)
|
|
552
515
|
console.log(` Backed up ${backups} replaced local cop${backups === 1 ? 'y' : 'ies'} in ~/.codeep/backups/personalities/.`);
|
|
553
516
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
517
|
+
else if (personalities.removed === 0) {
|
|
518
|
+
console.log(' Agents already up to date.');
|
|
519
|
+
}
|
|
520
|
+
if (personalities.ok && personalities.removed > 0) {
|
|
521
|
+
console.log(` Removed ${personalities.removed} agent${personalities.removed === 1 ? '' : 's'} deleted on codeep.dev (backed up first).`);
|
|
522
|
+
}
|
|
523
|
+
const commands = await pullCommands();
|
|
524
|
+
if (!commands.ok) {
|
|
525
|
+
console.log(` Could not pull custom commands — ${describeSyncFailure(commands.reason)}.`);
|
|
526
|
+
}
|
|
527
|
+
else if (commands.count > 0) {
|
|
528
|
+
console.log(` Pulled ${commands.count} custom command${commands.count === 1 ? '' : 's'}.`);
|
|
557
529
|
}
|
|
558
530
|
const profPulled = await pullUserProfile();
|
|
559
531
|
if (profPulled === 1) {
|
|
@@ -597,13 +569,20 @@ Commands (in chat):
|
|
|
597
569
|
}
|
|
598
570
|
// Also push portable personal config — personalities + commands + profile.
|
|
599
571
|
const { pushPersonalities, pushCommands, pushUserProfile } = await import('../utils/codeepCloud.js');
|
|
600
|
-
const
|
|
601
|
-
|
|
602
|
-
|
|
572
|
+
const { describeSyncFailure } = await import('../utils/codeepCloud.js');
|
|
573
|
+
const personalities = await pushPersonalities();
|
|
574
|
+
if (!personalities.ok) {
|
|
575
|
+
console.log(` Could not push agents — ${describeSyncFailure(personalities.reason)}.`);
|
|
576
|
+
}
|
|
577
|
+
else if (personalities.count > 0) {
|
|
578
|
+
console.log(` Pushed ${personalities.count} personalit${personalities.count === 1 ? 'y' : 'ies'}.`);
|
|
579
|
+
}
|
|
580
|
+
const commands = await pushCommands();
|
|
581
|
+
if (!commands.ok) {
|
|
582
|
+
console.log(` Could not push custom commands — ${describeSyncFailure(commands.reason)}.`);
|
|
603
583
|
}
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
console.log(` Pushed ${cCount} custom command${cCount === 1 ? '' : 's'}.`);
|
|
584
|
+
else if (commands.count > 0) {
|
|
585
|
+
console.log(` Pushed ${commands.count} custom command${commands.count === 1 ? '' : 's'}.`);
|
|
607
586
|
}
|
|
608
587
|
if (await pushUserProfile()) {
|
|
609
588
|
console.log(' Pushed your profile (about you).');
|
package/dist/utils/agent.d.ts
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { ProjectContext } from './project';
|
|
7
7
|
import { loadProjectRules, loadProgressLog, writeProgressLog, formatChatHistoryForAgent } from './agentChat';
|
|
8
8
|
import type { AgentChatResponse } from './agentChat';
|
|
9
|
+
import { type Personality } from './personalities';
|
|
9
10
|
export { loadProjectRules, loadProgressLog, writeProgressLog, formatChatHistoryForAgent };
|
|
10
11
|
export type { AgentChatResponse };
|
|
11
12
|
import { ToolCall, ToolResult, ActionLog } from './tools';
|
|
@@ -83,6 +84,12 @@ export interface AgentOptions {
|
|
|
83
84
|
* sub-agent's tool actions still record into the parent's session, so undo
|
|
84
85
|
* spans delegation. */
|
|
85
86
|
nested?: boolean;
|
|
87
|
+
/** Run under this capability boundary instead of whatever the user has
|
|
88
|
+
* selected. Used by non-interactive callers that must pin the boundary
|
|
89
|
+
* themselves — a CI fix, for example, runs files+tests regardless of the
|
|
90
|
+
* machine's active bot. Enforced by the same gate as any other bot; this
|
|
91
|
+
* chooses which one applies, never whether one does. */
|
|
92
|
+
personalityOverride?: Personality;
|
|
86
93
|
/** Delegation depth. 0 = top-level orchestrator (gets the `delegate` tool);
|
|
87
94
|
* sub-agents run at depth 1 and cannot delegate further (v1). */
|
|
88
95
|
depth?: number;
|