compact-agent 1.29.1 → 1.30.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/dist/config.d.ts +3 -4
- package/dist/config.js +25 -14
- package/dist/config.js.map +1 -1
- package/dist/index.js +92 -14
- package/dist/index.js.map +1 -1
- package/dist/query.js +83 -4
- package/dist/query.js.map +1 -1
- package/dist/sessions.d.ts +24 -0
- package/dist/sessions.js +74 -5
- package/dist/sessions.js.map +1 -1
- package/package.json +1 -1
package/dist/config.d.ts
CHANGED
|
@@ -11,10 +11,9 @@ export declare const LEGACY_CONFIG_DIR_NAME = ".crowcoder";
|
|
|
11
11
|
export declare function getProjectStateDir(cwd: string): string;
|
|
12
12
|
export declare function getConfigDir(): string;
|
|
13
13
|
/**
|
|
14
|
-
* Same as
|
|
15
|
-
* modules
|
|
16
|
-
*
|
|
17
|
-
* `join(homedir(), '.crowcoder')`.
|
|
14
|
+
* Same as getConfigDir() but exported under a clearer name for
|
|
15
|
+
* other modules that want the home-dir state root. Used by
|
|
16
|
+
* sessions, debug log, gateguard state, etc.
|
|
18
17
|
*/
|
|
19
18
|
export declare function getHomeStateDir(): string;
|
|
20
19
|
export declare function loadConfig(): CrowcoderConfig;
|
package/dist/config.js
CHANGED
|
@@ -14,10 +14,21 @@ import { homedir } from 'node:os';
|
|
|
14
14
|
// skills, memory etc. without any manual step.
|
|
15
15
|
export const CONFIG_DIR_NAME = '.compact-agent';
|
|
16
16
|
export const LEGACY_CONFIG_DIR_NAME = '.crowcoder';
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
// Resolve the config dir LAZILY (every call) instead of caching at
|
|
18
|
+
// module-load time. The cached form prevented tests + sandboxed runs
|
|
19
|
+
// from overriding via COMPACT_AGENT_HOME after the first import: the
|
|
20
|
+
// first module to load would freeze the path at the user's real
|
|
21
|
+
// home, and all subsequent overrides were ignored. The resolution
|
|
22
|
+
// is cheap (env lookup + one join) so calling per access has no
|
|
23
|
+
// observable cost on the hot path.
|
|
24
|
+
function resolveConfigDir() {
|
|
25
|
+
return (process.env.COMPACT_AGENT_HOME ||
|
|
26
|
+
process.env.CROWCODER_HOME ||
|
|
27
|
+
join(homedir(), CONFIG_DIR_NAME));
|
|
28
|
+
}
|
|
29
|
+
function resolveConfigFile() {
|
|
30
|
+
return join(resolveConfigDir(), 'config.json');
|
|
31
|
+
}
|
|
21
32
|
// Tracks whether we've already attempted the legacy-dir migration this
|
|
22
33
|
// process. Migration is idempotent (existsSync guard) but we still cache
|
|
23
34
|
// the decision so loadConfig() can be called repeatedly without re-stat'ing.
|
|
@@ -161,25 +172,25 @@ const DEFAULT_CONFIG = {
|
|
|
161
172
|
},
|
|
162
173
|
};
|
|
163
174
|
export function getConfigDir() {
|
|
164
|
-
return
|
|
175
|
+
return resolveConfigDir();
|
|
165
176
|
}
|
|
166
177
|
/**
|
|
167
|
-
* Same as
|
|
168
|
-
* modules
|
|
169
|
-
*
|
|
170
|
-
* `join(homedir(), '.crowcoder')`.
|
|
178
|
+
* Same as getConfigDir() but exported under a clearer name for
|
|
179
|
+
* other modules that want the home-dir state root. Used by
|
|
180
|
+
* sessions, debug log, gateguard state, etc.
|
|
171
181
|
*/
|
|
172
182
|
export function getHomeStateDir() {
|
|
173
|
-
return
|
|
183
|
+
return resolveConfigDir();
|
|
174
184
|
}
|
|
175
185
|
export function loadConfig() {
|
|
176
186
|
// Try to migrate legacy ~/.crowcoder → ~/.compact-agent before reading.
|
|
177
187
|
migrateLegacyHomeDir();
|
|
178
|
-
|
|
188
|
+
const configFile = resolveConfigFile();
|
|
189
|
+
if (!existsSync(configFile)) {
|
|
179
190
|
return { ...DEFAULT_CONFIG };
|
|
180
191
|
}
|
|
181
192
|
try {
|
|
182
|
-
const raw = readFileSync(
|
|
193
|
+
const raw = readFileSync(configFile, 'utf-8');
|
|
183
194
|
const loaded = JSON.parse(raw);
|
|
184
195
|
const config = { ...DEFAULT_CONFIG, ...loaded };
|
|
185
196
|
validateConfig(config);
|
|
@@ -229,8 +240,8 @@ function validateConfig(config) {
|
|
|
229
240
|
}
|
|
230
241
|
}
|
|
231
242
|
export function saveConfig(config) {
|
|
232
|
-
mkdirSync(
|
|
233
|
-
writeFileSync(
|
|
243
|
+
mkdirSync(resolveConfigDir(), { recursive: true });
|
|
244
|
+
writeFileSync(resolveConfigFile(), JSON.stringify(config, null, 2), 'utf-8');
|
|
234
245
|
}
|
|
235
246
|
export function configExists() {
|
|
236
247
|
const cfg = loadConfig();
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACzG,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,wEAAwE;AACxE,yEAAyE;AACzE,EAAE;AACF,sEAAsE;AACtE,4DAA4D;AAC5D,4CAA4C;AAC5C,EAAE;AACF,0EAA0E;AAC1E,0EAA0E;AAC1E,0EAA0E;AAC1E,+CAA+C;AAC/C,MAAM,CAAC,MAAM,eAAe,GAAG,gBAAgB,CAAC;AAChD,MAAM,CAAC,MAAM,sBAAsB,GAAG,YAAY,CAAC;AAEnD,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,aAAa,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACzG,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGlC,wEAAwE;AACxE,yEAAyE;AACzE,EAAE;AACF,sEAAsE;AACtE,4DAA4D;AAC5D,4CAA4C;AAC5C,EAAE;AACF,0EAA0E;AAC1E,0EAA0E;AAC1E,0EAA0E;AAC1E,+CAA+C;AAC/C,MAAM,CAAC,MAAM,eAAe,GAAG,gBAAgB,CAAC;AAChD,MAAM,CAAC,MAAM,sBAAsB,GAAG,YAAY,CAAC;AAEnD,mEAAmE;AACnE,qEAAqE;AACrE,qEAAqE;AACrE,gEAAgE;AAChE,kEAAkE;AAClE,gEAAgE;AAChE,mCAAmC;AACnC,SAAS,gBAAgB;IACvB,OAAO,CACL,OAAO,CAAC,GAAG,CAAC,kBAAkB;QAC9B,OAAO,CAAC,GAAG,CAAC,cAAc;QAC1B,IAAI,CAAC,OAAO,EAAE,EAAE,eAAe,CAAC,CACjC,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB;IACxB,OAAO,IAAI,CAAC,gBAAgB,EAAE,EAAE,aAAa,CAAC,CAAC;AACjD,CAAC;AAED,uEAAuE;AACvE,yEAAyE;AACzE,6EAA6E;AAC7E,IAAI,uBAAuB,GAAG,KAAK,CAAC;AAEpC;;;;;;;;;;;;;;GAcG;AACH,SAAS,oBAAoB;IAC3B,IAAI,uBAAuB;QAAE,OAAO;IACpC,uBAAuB,GAAG,IAAI,CAAC;IAE/B,uDAAuD;IACvD,IAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,IAAI,OAAO,CAAC,GAAG,CAAC,cAAc;QAAE,OAAO;IAEzE,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,eAAe,CAAC,CAAC;IAChD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,sBAAsB,CAAC,CAAC;IAE1D,IAAI,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO;IAEzD,IAAI,CAAC;QACH,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;QAC9B,OAAO,CAAC,IAAI,CACV,oBAAoB,sBAAsB,QAAQ,eAAe,6CAA6C,CAC/G,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,oEAAoE;QACpE,+DAA+D;QAC/D,IAAI,CAAC;YACH,MAAM,CAAC,SAAS,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC/C,MAAM,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;YACpD,OAAO,CAAC,IAAI,CACV,oBAAoB,sBAAsB,QAAQ,eAAe,eAAe,CACjF,CAAC;QACJ,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CACV,qCAAqC,sBAAsB,QAAQ,eAAe,KAAK,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,6DAA6D,CAC7L,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,kBAAkB,CAAC,GAAW;IAC5C,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,sBAAsB,CAAC,CAAC;IACpD,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,SAAS,CAAC;IACnE,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,cAAc,GAAoB;IACtC,MAAM,EAAE,EAAE;IACV,OAAO,EAAE,8BAA8B;IACvC,KAAK,EAAE,2BAA2B;IAClC,gEAAgE;IAChE,mEAAmE;IACnE,gEAAgE;IAChE,oEAAoE;IACpE,4DAA4D;IAC5D,aAAa,EAAE,2BAA2B;IAC1C,QAAQ,EAAE,YAAY;IACtB,SAAS,EAAE,IAAI;IACf,WAAW,EAAE,GAAG;IAChB,cAAc,EAAE,KAAK;IACrB,sEAAsE;IACtE,wEAAwE;IACxE,OAAO,EAAE,cAAc;IACvB,4EAA4E;IAC5E,+DAA+D;IAC/D,YAAY,EAAE,IAAI;IAClB,6DAA6D;IAC7D,mEAAmE;IACnE,wEAAwE;IACxE,sBAAsB;IACtB,OAAO,EAAE;QACP,KAAK,EAAE,KAAK;KACb;IACD,2EAA2E;IAC3E,wEAAwE;IACxE,2EAA2E;IAC3E,mDAAmD;IACnD,MAAM,EAAE;QACN,OAAO,EAAE,IAAI;QACb,WAAW,EAAE,IAAI;QACjB,YAAY,EAAE,IAAI;KACnB;IACD,4EAA4E;IAC5E,sEAAsE;IACtE,4EAA4E;IAC5E,oDAAoD;IACpD,KAAK,EAAE;QACL,OAAO,EAAE,KAAK;QACd,GAAG,EAAE;YACH,sEAAsE;YACtE,oEAAoE;YACpE,sEAAsE;YACtE,gBAAgB;YAChB,OAAO,EAAE,2BAA2B;YACpC,KAAK,EAAE,WAAW;YAClB,YAAY,EAAE,IAAI;YAClB,UAAU,EAAE,KAAK;SAClB;QACD,GAAG,EAAE;YACH,uEAAuE;YACvE,wCAAwC;YACxC,OAAO,EAAE,8BAA8B;YACvC,KAAK,EAAE,mBAAmB;YAC1B,sEAAsE;YACtE,iEAAiE;YACjE,4BAA4B;YAC5B,gBAAgB,EAAE,sBAAsB;YACxC,WAAW,EAAE,sBAAsB;YACnC,QAAQ,EAAE,IAAI;YACd,QAAQ,EAAE,IAAI;YACd,KAAK,EAAE,GAAG;YACV,SAAS,EAAE,GAAG;YACd,eAAe,EAAE,IAAI;SACtB;QACD,aAAa,EAAE;YACb,sEAAsE;YACtE,wEAAwE;YACxE,mBAAmB;YACnB,YAAY,EAAE,KAAK;YACnB,SAAS,EAAE,IAAI;YACf,cAAc,EAAE,IAAI;YACpB,oBAAoB,EAAE,IAAI;YAC1B,oBAAoB,EAAE,IAAI;YAC1B,qBAAqB,EAAE,GAAG;SAC3B;KACF;CACF,CAAC;AAEF,MAAM,UAAU,YAAY;IAC1B,OAAO,gBAAgB,EAAE,CAAC;AAC5B,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,gBAAgB,EAAE,CAAC;AAC5B,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,wEAAwE;IACxE,oBAAoB,EAAE,CAAC;IACvB,MAAM,UAAU,GAAG,iBAAiB,EAAE,CAAC;IACvC,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAC5B,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC/B,CAAC;IACD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;QAC9C,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QAC/B,MAAM,MAAM,GAAG,EAAE,GAAG,cAAc,EAAE,GAAG,MAAM,EAAE,CAAC;QAChD,cAAc,CAAC,MAAM,CAAC,CAAC;QACvB,OAAO,MAAM,CAAC;IAChB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,IAAI,CAAC,mCAAmC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC;QAC5F,OAAO,EAAE,GAAG,cAAc,EAAE,CAAC;IAC/B,CAAC;AACH,CAAC;AAED,2EAA2E;AAC3E,0EAA0E;AAC1E,yEAAyE;AACzE,2EAA2E;AAC3E,0EAA0E;AAC1E,8CAA8C;AAC9C,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAAU,CAAC;AAE/C,SAAS,cAAc,CAAC,MAAuB;IAC7C,mBAAmB;IACnB,IAAI,MAAM,CAAC,OAAO,IAAI,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QACzD,IAAI,CAAC;YACH,IAAI,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC1B,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,IAAI,CAAC,6BAA6B,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;YAC5D,MAAM,CAAC,OAAO,GAAG,cAAc,CAAC,OAAO,CAAC;QAC1C,CAAC;IACH,CAAC;IAED,iBAAiB;IACjB,IAAI,CAAC,MAAM,CAAC,KAAK,IAAI,OAAO,MAAM,CAAC,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;QACpF,OAAO,CAAC,IAAI,CAAC,4CAA4C,CAAC,CAAC;QAC3D,MAAM,CAAC,KAAK,GAAG,cAAc,CAAC,KAAK,CAAC;IACtC,CAAC;IAED,0BAA0B;IAC1B,MAAM,UAAU,GAAwC,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAChF,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,oCAAoC,MAAM,CAAC,cAAc,eAAe,CAAC,CAAC;QACvF,MAAM,CAAC,cAAc,GAAG,KAAK,CAAC;IAChC,CAAC;IAED,4BAA4B;IAC5B,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,OAAO,EAAE,eAAe,EAAE,UAAU,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,gBAAgB,EAAE,oBAAoB,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,OAAO,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;IACnQ,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC/D,oBAAoB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAC9B,OAAO,CAAC,IAAI,CAAC,qCAAqC,GAAG,EAAE,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,MAAuB;IAChD,SAAS,CAAC,gBAAgB,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,aAAa,CAAC,iBAAiB,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AAC/E,CAAC;AAED,MAAM,UAAU,YAAY;IAC1B,MAAM,GAAG,GAAG,UAAU,EAAE,CAAC;IACzB,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,IAAI,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED,SAAS,WAAW,CAAC,GAAoB;IACvC,sCAAsC;IACtC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;AAClF,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -13,7 +13,7 @@ import { runQuery } from './query.js';
|
|
|
13
13
|
import { ALL_TOOLS } from './tools/index.js';
|
|
14
14
|
import { PROVIDERS } from './types.js';
|
|
15
15
|
// New systems
|
|
16
|
-
import { createSession, autoSave, listSessions, loadSession, deleteSession, saveSession, generateSessionId } from './sessions.js';
|
|
16
|
+
import { createSession, autoSave, listSessions, loadSession, deleteSession, saveSession, generateSessionId, resolveSessionRef } from './sessions.js';
|
|
17
17
|
import { initHooksDir, runHooks, listHooks, saveHooksConfig, clearQuarantinedHooks } from './hooks.js';
|
|
18
18
|
import { printUsageSummary, setBudget } from './cost-tracker.js';
|
|
19
19
|
import { getCompactionStats } from './compaction.js';
|
|
@@ -777,11 +777,18 @@ export function handleSlashCommand(input, config, messages, session, mode) {
|
|
|
777
777
|
}
|
|
778
778
|
else {
|
|
779
779
|
console.log(chalk.cyan(`\n Saved Sessions (${sessions.length}):`));
|
|
780
|
+
// Show the FULL ID. Previously we truncated to 12 chars for
|
|
781
|
+
// visual density, but users copy-paste the displayed string
|
|
782
|
+
// into /resume and the truncated form doesn't match the
|
|
783
|
+
// actual filename — every paste failed. Width-aware padding
|
|
784
|
+
// keeps the table aligned across rows of differing ID
|
|
785
|
+
// lengths.
|
|
786
|
+
const maxIdLen = Math.max(...sessions.map((s) => s.id.length));
|
|
780
787
|
for (const s of sessions.slice(0, 20)) {
|
|
781
|
-
console.log(chalk.white(` ${s.id.
|
|
788
|
+
console.log(chalk.white(` ${s.id.padEnd(maxIdLen + 2)}`) +
|
|
782
789
|
chalk.dim(`${s.name.padEnd(30)} ${s.turnCount} turns ${s.model} ${s.updatedAt.slice(0, 10)}`));
|
|
783
790
|
}
|
|
784
|
-
console.log();
|
|
791
|
+
console.log(chalk.dim(`\n Use /resume <id>, /resume <prefix>, or /resume last to restore one.`));
|
|
785
792
|
}
|
|
786
793
|
return { handled: true };
|
|
787
794
|
}
|
|
@@ -791,26 +798,61 @@ export function handleSlashCommand(input, config, messages, session, mode) {
|
|
|
791
798
|
console.log(chalk.green(` Session saved: ${session.id} "${session.name}"`));
|
|
792
799
|
return { handled: true };
|
|
793
800
|
case '/resume': {
|
|
794
|
-
if (!args) {
|
|
795
|
-
console.log(chalk.yellow(' Usage: /resume <session-id>'));
|
|
801
|
+
if (!args.trim()) {
|
|
802
|
+
console.log(chalk.yellow(' Usage: /resume <session-id> | <prefix> | last'));
|
|
803
|
+
console.log(chalk.dim(' /sessions lists what\'s saved.'));
|
|
796
804
|
return { handled: true };
|
|
797
805
|
}
|
|
798
|
-
|
|
806
|
+
// resolveSessionRef accepts exact ID, prefix match (like git),
|
|
807
|
+
// "last"/"latest" shortcut, and strips angle/quote wrappers
|
|
808
|
+
// (users pasting /resume <id> from the help text). This
|
|
809
|
+
// replaces the exact-only lookup that broke for everyone
|
|
810
|
+
// who copy-pasted from /sessions's previously-truncated
|
|
811
|
+
// display.
|
|
812
|
+
const ref = resolveSessionRef(args);
|
|
813
|
+
if ('error' in ref) {
|
|
814
|
+
console.log(chalk.red(` ${ref.error}`));
|
|
815
|
+
if (ref.candidates && ref.candidates.length > 0) {
|
|
816
|
+
console.log(chalk.dim(' Matching candidates:'));
|
|
817
|
+
for (const c of ref.candidates.slice(0, 8))
|
|
818
|
+
console.log(chalk.dim(` ${c}`));
|
|
819
|
+
}
|
|
820
|
+
return { handled: true };
|
|
821
|
+
}
|
|
822
|
+
const loaded = loadSession(ref.id);
|
|
799
823
|
if (!loaded) {
|
|
800
|
-
|
|
824
|
+
// Resolver said the file exists but loadSession returned
|
|
825
|
+
// null — corrupt JSON. Surface clearly rather than silently
|
|
826
|
+
// looking like a not-found.
|
|
827
|
+
console.log(chalk.red(` Session ${ref.id} resolved but its JSON is corrupt.`));
|
|
801
828
|
return { handled: true };
|
|
802
829
|
}
|
|
803
830
|
console.log(chalk.green(` Resumed: ${loaded.name} (${loaded.messages.length} messages)`));
|
|
804
831
|
return { handled: true, newMessages: loaded.messages };
|
|
805
832
|
}
|
|
806
|
-
case '/delete':
|
|
807
|
-
if (args
|
|
808
|
-
console.log(chalk.
|
|
833
|
+
case '/delete': {
|
|
834
|
+
if (!args.trim()) {
|
|
835
|
+
console.log(chalk.yellow(' Usage: /delete <session-id> | <prefix> | last'));
|
|
836
|
+
return { handled: true };
|
|
837
|
+
}
|
|
838
|
+
const ref = resolveSessionRef(args);
|
|
839
|
+
if ('error' in ref) {
|
|
840
|
+
console.log(chalk.yellow(` ${ref.error}`));
|
|
841
|
+
if (ref.candidates && ref.candidates.length > 0) {
|
|
842
|
+
console.log(chalk.dim(' Matching candidates:'));
|
|
843
|
+
for (const c of ref.candidates.slice(0, 8))
|
|
844
|
+
console.log(chalk.dim(` ${c}`));
|
|
845
|
+
}
|
|
846
|
+
return { handled: true };
|
|
847
|
+
}
|
|
848
|
+
if (deleteSession(ref.id)) {
|
|
849
|
+
console.log(chalk.green(` Deleted session: ${ref.id}`));
|
|
809
850
|
}
|
|
810
851
|
else {
|
|
811
|
-
console.log(chalk.yellow(`
|
|
852
|
+
console.log(chalk.yellow(` Could not delete session: ${ref.id}`));
|
|
812
853
|
}
|
|
813
854
|
return { handled: true };
|
|
855
|
+
}
|
|
814
856
|
// ── Git ───────────────────────────────────────────
|
|
815
857
|
case '/commit': {
|
|
816
858
|
const prompt = buildCommitPrompt(process.cwd());
|
|
@@ -1805,16 +1847,52 @@ export function handleSlashCommand(input, config, messages, session, mode) {
|
|
|
1805
1847
|
}
|
|
1806
1848
|
return { handled: false, injectPrompt: buildStitchPrompt(args) };
|
|
1807
1849
|
case '/stitch-config': {
|
|
1808
|
-
|
|
1850
|
+
// Sanitize the input. Users routinely paste keys with the
|
|
1851
|
+
// angle-bracket placeholder wrappers from documentation
|
|
1852
|
+
// (`<KEY>`), with surrounding quotes from a shell escape, or
|
|
1853
|
+
// with whitespace from clipboard managers. Without this
|
|
1854
|
+
// stripping the key gets stored literally (e.g. "<AQ.…>") and
|
|
1855
|
+
// every subsequent Stitch call fails auth — a real failure
|
|
1856
|
+
// mode that wasted hours in user testing.
|
|
1857
|
+
let key = args.trim();
|
|
1858
|
+
// Strip a paired wrap: <...>, "...", '...', `...`, [...], (...)
|
|
1859
|
+
const wraps = [
|
|
1860
|
+
['<', '>'], ['"', '"'], ["'", "'"], ['`', '`'], ['[', ']'], ['(', ')'],
|
|
1861
|
+
];
|
|
1862
|
+
for (const [open, close] of wraps) {
|
|
1863
|
+
if (key.startsWith(open) && key.endsWith(close) && key.length > 2) {
|
|
1864
|
+
key = key.slice(1, -1).trim();
|
|
1865
|
+
break;
|
|
1866
|
+
}
|
|
1867
|
+
}
|
|
1809
1868
|
if (!key) {
|
|
1810
1869
|
console.log(chalk.yellow(' Usage: /stitch-config <api-key>'));
|
|
1811
1870
|
console.log(chalk.dim(' Get a key from https://stitch.withgoogle.com/ → Stitch Settings → API Keys'));
|
|
1871
|
+
console.log(chalk.dim(' Paste the key alone, not wrapped in angle brackets or quotes.'));
|
|
1812
1872
|
return { handled: true };
|
|
1813
1873
|
}
|
|
1874
|
+
// Shape sanity-check. Stitch API keys start with "AQ." per the
|
|
1875
|
+
// Google API-key convention. Warn if the shape looks wrong,
|
|
1876
|
+
// but still save — we don't want to false-reject a future
|
|
1877
|
+
// format change.
|
|
1878
|
+
if (!/^AQ\./i.test(key)) {
|
|
1879
|
+
console.log(chalk.yellow(' Warning: this key doesn\'t look like a Stitch API key (expected to start with "AQ.").'));
|
|
1880
|
+
console.log(chalk.dim(' Saved anyway. If Stitch calls fail with auth errors, double-check what you pasted.'));
|
|
1881
|
+
}
|
|
1814
1882
|
saveStitchConfig(key);
|
|
1815
1883
|
console.log(chalk.green(` Stitch API key saved to ~/.compact-agent/stitch.json`));
|
|
1816
|
-
|
|
1817
|
-
|
|
1884
|
+
// The stitch tool is only added to ALL_TOOLS at module-load
|
|
1885
|
+
// time (when src/tools/index.ts is first imported). Mid-session
|
|
1886
|
+
// configuration won't make it appear until the user restarts.
|
|
1887
|
+
// Make the restart requirement IMPOSSIBLE to miss — previous
|
|
1888
|
+
// versions buried this in dim text and the model wasted turns
|
|
1889
|
+
// hallucinating MCP endpoints when the tool was missing.
|
|
1890
|
+
console.log('');
|
|
1891
|
+
console.log(chalk.yellow.bold(' ⚠ RESTART REQUIRED'));
|
|
1892
|
+
console.log(chalk.yellow(' The `stitch` tool is registered only at REPL launch. Type /exit'));
|
|
1893
|
+
console.log(chalk.yellow(' and re-run compact-agent to make it available to the agent.'));
|
|
1894
|
+
console.log(chalk.dim(' Until then, /design and Stitch-related requests will see the model'));
|
|
1895
|
+
console.log(chalk.dim(' fall back to hand-coded HTML/CSS instead of using Stitch.'));
|
|
1818
1896
|
return { handled: true };
|
|
1819
1897
|
}
|
|
1820
1898
|
// ── API key pool (multi-account rotation) ────────────────
|