byterover-cli 1.0.4 → 1.0.5

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.
Files changed (72) hide show
  1. package/README.md +13 -2
  2. package/dist/commands/curate.js +1 -1
  3. package/dist/commands/main.d.ts +13 -0
  4. package/dist/commands/main.js +53 -2
  5. package/dist/commands/query.js +1 -1
  6. package/dist/constants.d.ts +1 -1
  7. package/dist/constants.js +1 -1
  8. package/dist/core/domain/cipher/llm/registry.js +53 -2
  9. package/dist/core/domain/cipher/llm/types.d.ts +2 -0
  10. package/dist/core/domain/cipher/process/types.d.ts +7 -0
  11. package/dist/core/domain/cipher/session/session-metadata.d.ts +178 -0
  12. package/dist/core/domain/cipher/session/session-metadata.js +147 -0
  13. package/dist/core/domain/knowledge/markdown-writer.d.ts +15 -18
  14. package/dist/core/domain/knowledge/markdown-writer.js +232 -34
  15. package/dist/core/domain/knowledge/relation-parser.d.ts +25 -39
  16. package/dist/core/domain/knowledge/relation-parser.js +39 -61
  17. package/dist/core/domain/transport/schemas.d.ts +37 -2
  18. package/dist/core/domain/transport/schemas.js +23 -2
  19. package/dist/core/interfaces/cipher/i-session-persistence.d.ts +133 -0
  20. package/dist/core/interfaces/cipher/i-session-persistence.js +7 -0
  21. package/dist/core/interfaces/cipher/message-types.d.ts +6 -0
  22. package/dist/core/interfaces/executor/i-curate-executor.d.ts +2 -2
  23. package/dist/core/interfaces/i-context-file-reader.d.ts +3 -0
  24. package/dist/core/interfaces/usecase/{i-clear-use-case.d.ts → i-reset-use-case.d.ts} +1 -1
  25. package/dist/infra/cipher/agent/agent-schemas.d.ts +6 -6
  26. package/dist/infra/cipher/agent/service-initializer.js +4 -4
  27. package/dist/infra/cipher/file-system/context-tree-file-system-factory.js +3 -2
  28. package/dist/infra/cipher/file-system/file-system-service.js +1 -0
  29. package/dist/infra/cipher/http/internal-llm-http-service.js +3 -5
  30. package/dist/infra/cipher/interactive-loop.js +3 -1
  31. package/dist/infra/cipher/llm/context/context-manager.js +40 -16
  32. package/dist/infra/cipher/llm/formatters/gemini-formatter.d.ts +13 -0
  33. package/dist/infra/cipher/llm/formatters/gemini-formatter.js +98 -6
  34. package/dist/infra/cipher/llm/generators/byterover-content-generator.js +6 -2
  35. package/dist/infra/cipher/llm/thought-parser.d.ts +21 -0
  36. package/dist/infra/cipher/llm/thought-parser.js +27 -0
  37. package/dist/infra/cipher/llm/tool-output-processor.d.ts +10 -0
  38. package/dist/infra/cipher/llm/tool-output-processor.js +80 -7
  39. package/dist/infra/cipher/process/process-service.js +11 -3
  40. package/dist/infra/cipher/session/chat-session.d.ts +7 -2
  41. package/dist/infra/cipher/session/chat-session.js +90 -52
  42. package/dist/infra/cipher/session/session-metadata-store.d.ts +52 -0
  43. package/dist/infra/cipher/session/session-metadata-store.js +406 -0
  44. package/dist/infra/cipher/tools/implementations/curate-tool.js +113 -35
  45. package/dist/infra/cipher/tools/implementations/task-tool.js +1 -0
  46. package/dist/infra/context-tree/file-context-file-reader.js +4 -0
  47. package/dist/infra/core/task-processor.d.ts +2 -2
  48. package/dist/infra/process/process-manager.d.ts +10 -1
  49. package/dist/infra/process/process-manager.js +16 -6
  50. package/dist/infra/process/transport-handlers.js +31 -0
  51. package/dist/infra/repl/commands/index.js +5 -2
  52. package/dist/infra/repl/commands/new-command.d.ts +14 -0
  53. package/dist/infra/repl/commands/new-command.js +61 -0
  54. package/dist/infra/repl/commands/{clear-command.d.ts → reset-command.d.ts} +2 -2
  55. package/dist/infra/repl/commands/{clear-command.js → reset-command.js} +10 -10
  56. package/dist/infra/usecase/generate-rules-use-case.js +2 -2
  57. package/dist/infra/usecase/init-use-case.js +4 -4
  58. package/dist/infra/usecase/logout-use-case.js +1 -1
  59. package/dist/infra/usecase/push-use-case.js +1 -1
  60. package/dist/infra/usecase/{clear-use-case.d.ts → reset-use-case.d.ts} +5 -5
  61. package/dist/infra/usecase/{clear-use-case.js → reset-use-case.js} +5 -5
  62. package/dist/resources/prompts/curate.yml +68 -13
  63. package/dist/resources/tools/curate.txt +60 -15
  64. package/dist/tui/components/inline-prompts/inline-confirm.js +2 -2
  65. package/dist/tui/components/onboarding/onboarding-flow.js +1 -0
  66. package/dist/tui/views/command-view.js +15 -0
  67. package/dist/utils/file-validator.js +9 -7
  68. package/oclif.manifest.json +3 -3
  69. package/package.json +1 -1
  70. package/dist/config/context-tree-domains.d.ts +0 -29
  71. package/dist/config/context-tree-domains.js +0 -29
  72. /package/dist/core/interfaces/usecase/{i-clear-use-case.js → i-reset-use-case.js} +0 -0
@@ -1,6 +1,7 @@
1
1
  import { readFile } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
3
  import { BRV_DIR, CONTEXT_TREE_DIR } from '../../constants.js';
4
+ import { MarkdownWriter } from '../../core/domain/knowledge/markdown-writer.js';
4
5
  /**
5
6
  * Extracts the title from the first markdown heading in the content.
6
7
  * @param content - The file content
@@ -27,9 +28,12 @@ export class FileContextFileReader {
27
28
  try {
28
29
  const content = await readFile(fullPath, 'utf8');
29
30
  const title = extractTitle(content, relativePath);
31
+ const parsedContent = MarkdownWriter.parseContent(content, title);
30
32
  return {
31
33
  content,
34
+ narrative: parsedContent.narrative,
32
35
  path: relativePath,
36
+ rawConcept: parsedContent.rawConcept,
33
37
  title,
34
38
  };
35
39
  }
@@ -7,10 +7,10 @@ import type { IQueryExecutor } from '../../core/interfaces/executor/i-query-exec
7
7
  * Agent uses its default session (Single-Session pattern).
8
8
  */
9
9
  export type TaskInput = {
10
- /** Task content/prompt */
11
- content: string;
12
10
  /** Client's working directory for file validation */
13
11
  clientCwd?: string;
12
+ /** Task content/prompt */
13
+ content: string;
14
14
  /** Optional file paths for curate --files */
15
15
  files?: string[];
16
16
  /** Task ID */
@@ -47,6 +47,13 @@ export type ProcessManagerConfig = {
47
47
  /** Timeout for process startup (ms) */
48
48
  startupTimeoutMs?: number;
49
49
  };
50
+ /**
51
+ * Options for starting the process manager.
52
+ */
53
+ export type ProcessStartOptions = {
54
+ /** Session ID to pass to Agent process (for stateful sessions) */
55
+ sessionId?: string;
56
+ };
50
57
  /**
51
58
  * ProcessManager - Spawns and manages Transport and Agent processes.
52
59
  *
@@ -57,6 +64,7 @@ export type ProcessManagerConfig = {
57
64
  * - Crash recovery: respawn on exit
58
65
  */
59
66
  export declare class ProcessManager {
67
+ private currentSessionId?;
60
68
  private healthCheckInterval?;
61
69
  private lastHealthCheckTime;
62
70
  private readonly shutdownTimeoutMs;
@@ -84,9 +92,10 @@ export declare class ProcessManager {
84
92
  * 3. Start Agent Process with TRANSPORT_PORT env
85
93
  * 4. Wait for Agent 'ready'
86
94
  *
95
+ * @param options - Start options including session ID for stateful sessions
87
96
  * @throws Error if startup fails or times out
88
97
  */
89
- start(): Promise<void>;
98
+ start(options?: ProcessStartOptions): Promise<void>;
90
99
  /**
91
100
  * Stop all processes gracefully.
92
101
  *
@@ -46,6 +46,7 @@ function createSystemError(error, context) {
46
46
  * - Crash recovery: respawn on exit
47
47
  */
48
48
  export class ProcessManager {
49
+ currentSessionId;
49
50
  healthCheckInterval;
50
51
  lastHealthCheckTime = Date.now();
51
52
  shutdownTimeoutMs;
@@ -86,12 +87,15 @@ export class ProcessManager {
86
87
  * 3. Start Agent Process with TRANSPORT_PORT env
87
88
  * 4. Wait for Agent 'ready'
88
89
  *
90
+ * @param options - Start options including session ID for stateful sessions
89
91
  * @throws Error if startup fails or times out
90
92
  */
91
- async start() {
93
+ async start(options) {
92
94
  if (this.state.running) {
93
95
  return;
94
96
  }
97
+ // Store session ID for use when spawning agent
98
+ this.currentSessionId = options?.sessionId;
95
99
  // Step 1: Start Transport Process
96
100
  const port = await this.startTransportProcess();
97
101
  this.state.port = port;
@@ -235,12 +239,18 @@ export class ProcessManager {
235
239
  async startAgentProcess(transportPort) {
236
240
  return new Promise((resolve, reject) => {
237
241
  const workerPath = path.resolve(this.getWorkerDir(), 'agent-worker.js');
242
+ // Build environment variables for agent
243
+ const agentEnv = {
244
+ ...process.env,
245
+ BRV_SESSION_LOG: getSessionLogPath(),
246
+ TRANSPORT_PORT: String(transportPort),
247
+ };
248
+ // Pass session ID if provided (for stateful sessions)
249
+ if (this.currentSessionId) {
250
+ agentEnv.BYTEROVER_SESSION_ID = this.currentSessionId;
251
+ }
238
252
  const child = fork(workerPath, [], {
239
- env: {
240
- ...process.env,
241
- BRV_SESSION_LOG: getSessionLogPath(),
242
- TRANSPORT_PORT: String(transportPort),
243
- },
253
+ env: agentEnv,
244
254
  stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
245
255
  });
246
256
  this.state.agentProcess = child;
@@ -285,6 +285,37 @@ export class TransportHandlers {
285
285
  this.transport.broadcast(TransportAgentEventNames.RESTARTED, { error: data.error, success: false });
286
286
  }
287
287
  });
288
+ // agent:newSession - Client requests a new session (ends current, starts fresh)
289
+ this.transport.onRequest(TransportAgentEventNames.NEW_SESSION, (data, clientId) => {
290
+ transportLog(`New session requested by ${clientId}: ${data.reason ?? 'no reason'}`);
291
+ if (!this.agentClientId) {
292
+ return { error: 'Agent not connected', success: false };
293
+ }
294
+ // Forward new session command to Agent
295
+ this.transport.sendTo(this.agentClientId, TransportAgentEventNames.NEW_SESSION, { reason: data.reason });
296
+ // The actual response will come via agent:newSessionCreated event
297
+ // For now, return success to indicate the request was forwarded
298
+ return { success: true };
299
+ });
300
+ // agent:newSessionCreated - Agent reports new session creation result
301
+ this.transport.onRequest(TransportAgentEventNames.NEW_SESSION_CREATED, (data) => {
302
+ if (data.success) {
303
+ transportLog(`New session created: ${data.sessionId}`);
304
+ eventLog('agent:newSessionCreated', { sessionId: data.sessionId, success: true });
305
+ this.transport.broadcast(TransportAgentEventNames.NEW_SESSION_CREATED, {
306
+ sessionId: data.sessionId,
307
+ success: true,
308
+ });
309
+ }
310
+ else {
311
+ transportLog(`New session creation failed: ${data.error}`);
312
+ eventLog('agent:newSessionCreated', { error: data.error, success: false });
313
+ this.transport.broadcast(TransportAgentEventNames.NEW_SESSION_CREATED, {
314
+ error: data.error,
315
+ success: false,
316
+ });
317
+ }
318
+ });
288
319
  }
289
320
  /**
290
321
  * Setup Agent-related handlers.
@@ -1,12 +1,13 @@
1
- import { clearCommand } from './clear-command.js';
2
1
  import { curateCommand } from './curate-command.js';
3
2
  import { genRulesCommand } from './gen-rules-command.js';
4
3
  import { initCommand } from './init-command.js';
5
4
  import { loginCommand } from './login-command.js';
6
5
  import { logoutCommand } from './logout-command.js';
6
+ import { newCommand } from './new-command.js';
7
7
  import { pullCommand } from './pull-command.js';
8
8
  import { pushCommand } from './push-command.js';
9
9
  import { queryCommand } from './query-command.js';
10
+ import { resetCommand } from './reset-command.js';
10
11
  import { spaceCommand } from './space/index.js';
11
12
  import { statusCommand } from './status-command.js';
12
13
  /**
@@ -27,7 +28,9 @@ export const load = () => [
27
28
  spaceCommand, // Switch/list spaces
28
29
  // Context tree management
29
30
  genRulesCommand, // Generate rule files
30
- clearCommand, // Reset context tree (destructive)
31
+ resetCommand, // Reset context tree (destructive)
32
+ // Session management
33
+ newCommand, // Start fresh session (ends current, clears conversation)
31
34
  // Setup
32
35
  initCommand, // Project setup (once per project)
33
36
  // Auth
@@ -0,0 +1,14 @@
1
+ import { type SlashCommand } from '../../../tui/types.js';
2
+ /**
3
+ * /new command - Start a fresh session.
4
+ *
5
+ * This command:
6
+ * 1. Marks the current session as 'ended'
7
+ * 2. Creates a new session ID
8
+ * 3. Updates the active session pointer
9
+ * 4. Clears conversation history from the TUI view
10
+ *
11
+ * Note: This command does NOT affect the context tree (use /clear for that).
12
+ * The actual session switching is handled by command-view.tsx after this command executes.
13
+ */
14
+ export declare const newCommand: SlashCommand;
@@ -0,0 +1,61 @@
1
+ import { CommandKind } from '../../../tui/types.js';
2
+ import { ReplTerminal } from '../../terminal/repl-terminal.js';
3
+ import { Flags, parseReplArgs, toCommandFlags } from './arg-parser.js';
4
+ // Flags - defined once, used for both parsing and help display
5
+ const newFlags = {
6
+ yes: Flags.boolean({
7
+ char: 'y',
8
+ default: false,
9
+ description: 'Skip confirmation prompt',
10
+ }),
11
+ };
12
+ // Args - no args needed
13
+ const newArgs = {};
14
+ /**
15
+ * /new command - Start a fresh session.
16
+ *
17
+ * This command:
18
+ * 1. Marks the current session as 'ended'
19
+ * 2. Creates a new session ID
20
+ * 3. Updates the active session pointer
21
+ * 4. Clears conversation history from the TUI view
22
+ *
23
+ * Note: This command does NOT affect the context tree (use /clear for that).
24
+ * The actual session switching is handled by command-view.tsx after this command executes.
25
+ */
26
+ export const newCommand = {
27
+ action(_context, args) {
28
+ return {
29
+ async execute(onMessage, onPrompt) {
30
+ const terminal = new ReplTerminal({ onMessage, onPrompt });
31
+ const parsed = await parseReplArgs(args, {
32
+ args: newArgs,
33
+ flags: newFlags,
34
+ strict: false,
35
+ });
36
+ // Show confirmation unless -y flag is passed
37
+ if (!parsed.flags.yes) {
38
+ const confirmed = await terminal.confirm({
39
+ default: false,
40
+ message: 'Start a new session (ends current session and clears conversation history)',
41
+ });
42
+ if (!confirmed) {
43
+ terminal.log('Cancelled.');
44
+ return;
45
+ }
46
+ }
47
+ terminal.log('Starting new session...');
48
+ // The actual session creation is handled by command-view.tsx
49
+ // after this command completes. It sends agent:newSession event.
50
+ },
51
+ type: 'streaming',
52
+ };
53
+ },
54
+ aliases: [],
55
+ args: [],
56
+ autoExecute: true,
57
+ description: 'Start a fresh session (ends current session, clears conversation)',
58
+ flags: toCommandFlags(newFlags),
59
+ kind: CommandKind.BUILT_IN,
60
+ name: 'new',
61
+ };
@@ -1,5 +1,5 @@
1
1
  import { type SlashCommand } from '../../../tui/types.js';
2
2
  /**
3
- * clear command
3
+ * reset command
4
4
  */
5
- export declare const clearCommand: SlashCommand;
5
+ export declare const resetCommand: SlashCommand;
@@ -2,10 +2,10 @@ import { CommandKind } from '../../../tui/types.js';
2
2
  import { FileContextTreeService } from '../../context-tree/file-context-tree-service.js';
3
3
  import { FileContextTreeSnapshotService } from '../../context-tree/file-context-tree-snapshot-service.js';
4
4
  import { ReplTerminal } from '../../terminal/repl-terminal.js';
5
- import { ClearUseCase } from '../../usecase/clear-use-case.js';
5
+ import { ResetUseCase } from '../../usecase/reset-use-case.js';
6
6
  import { Args, Flags, parseReplArgs, toCommandFlags } from './arg-parser.js';
7
7
  // Flags - defined once, used for both parsing and help display
8
- const clearFlags = {
8
+ const resetFlags = {
9
9
  yes: Flags.boolean({
10
10
  char: 'y',
11
11
  default: false,
@@ -13,26 +13,26 @@ const clearFlags = {
13
13
  }),
14
14
  };
15
15
  // Args - defined once for parsing
16
- const clearArgs = {
16
+ const resetArgs = {
17
17
  directory: Args.string({
18
18
  description: 'Project directory (defaults to current directory)',
19
19
  required: false,
20
20
  }),
21
21
  };
22
22
  /**
23
- * clear command
23
+ * reset command
24
24
  */
25
- export const clearCommand = {
25
+ export const resetCommand = {
26
26
  action(_context, args) {
27
27
  return {
28
28
  async execute(onMessage, onPrompt) {
29
29
  const terminal = new ReplTerminal({ onMessage, onPrompt });
30
30
  const parsed = await parseReplArgs(args, {
31
- args: clearArgs,
32
- flags: clearFlags,
31
+ args: resetArgs,
32
+ flags: resetFlags,
33
33
  strict: false,
34
34
  });
35
- const useCase = new ClearUseCase({
35
+ const useCase = new ResetUseCase({
36
36
  contextTreeService: new FileContextTreeService(),
37
37
  contextTreeSnapshotService: new FileContextTreeSnapshotService(),
38
38
  terminal,
@@ -55,7 +55,7 @@ export const clearCommand = {
55
55
  ],
56
56
  autoExecute: true,
57
57
  description: 'Reset the current context tree and start with 6 default domains',
58
- flags: toCommandFlags(clearFlags),
58
+ flags: toCommandFlags(resetFlags),
59
59
  kind: CommandKind.BUILT_IN,
60
- name: 'clear',
60
+ name: 'reset',
61
61
  };
@@ -69,7 +69,7 @@ export class GenerateRulesUseCase {
69
69
  async promptForFileCreation(agent, filePath) {
70
70
  return this.terminal.confirm({
71
71
  default: true,
72
- message: `Rule file '${filePath}' doesn't exist. Create it with ByteRover rules?`,
72
+ message: `Rule file '${filePath}' doesn't exist. Create it with ByteRover rules`,
73
73
  });
74
74
  }
75
75
  /**
@@ -81,7 +81,7 @@ export class GenerateRulesUseCase {
81
81
  async promptForOverwriteConfirmation(agent) {
82
82
  return this.terminal.confirm({
83
83
  default: true,
84
- message: `Rule file already exists for ${agent}. Overwrite?`,
84
+ message: `Rule file already exists for ${agent}. Overwrite`,
85
85
  });
86
86
  }
87
87
  async run() {
@@ -81,7 +81,7 @@ export class InitUseCase {
81
81
  this.terminal.log(' - Regenerate rule instructions\n');
82
82
  return this.terminal.confirm({
83
83
  default: false,
84
- message: 'Continue with re-initialization?',
84
+ message: 'Continue with re-initialization',
85
85
  });
86
86
  }
87
87
  detectWorkspacesForAgent(agent) {
@@ -259,7 +259,7 @@ export class InitUseCase {
259
259
  this.terminal.log(' This folder and all its contents can be safely removed.\n');
260
260
  return this.terminal.confirm({
261
261
  default: true,
262
- message: 'Remove the ACE folder and its contents?',
262
+ message: 'Remove the ACE folder and its contents',
263
263
  });
264
264
  }
265
265
  /**
@@ -314,7 +314,7 @@ export class InitUseCase {
314
314
  async promptForFileCreation(agent, filePath) {
315
315
  return this.terminal.confirm({
316
316
  default: true,
317
- message: `Rule file '${filePath}' doesn't exist. Create it with ByteRover rules?`,
317
+ message: `Rule file '${filePath}' doesn't exist. Create it with ByteRover rules`,
318
318
  });
319
319
  }
320
320
  /**
@@ -324,7 +324,7 @@ export class InitUseCase {
324
324
  async promptForOverwriteConfirmation(agent) {
325
325
  return this.terminal.confirm({
326
326
  default: true,
327
- message: `Rule file already exists for ${agent}. Overwrite?`,
327
+ message: `Rule file already exists for ${agent}. Overwrite`,
328
328
  });
329
329
  }
330
330
  async promptForSpaceSelection(spaces) {
@@ -12,7 +12,7 @@ export class LogoutUseCase {
12
12
  async confirmLogout(userEmail) {
13
13
  return this.terminal.confirm({
14
14
  default: true,
15
- message: `Logging out ${userEmail}. Are you sure?`,
15
+ message: `Logging out ${userEmail}. Are you sure`,
16
16
  });
17
17
  }
18
18
  async run(options) {
@@ -106,7 +106,7 @@ export class PushUseCase {
106
106
  this.terminal.log(` Branch: ${branch}`);
107
107
  return this.terminal.confirm({
108
108
  default: false,
109
- message: 'Push to ByteRover?',
109
+ message: 'Push to ByteRover',
110
110
  });
111
111
  }
112
112
  async validateAuth() {
@@ -1,18 +1,18 @@
1
1
  import type { IContextTreeService } from '../../core/interfaces/i-context-tree-service.js';
2
2
  import type { IContextTreeSnapshotService } from '../../core/interfaces/i-context-tree-snapshot-service.js';
3
3
  import type { ITerminal } from '../../core/interfaces/i-terminal.js';
4
- import type { IClearUseCase } from '../../core/interfaces/usecase/i-clear-use-case.js';
5
- export interface ClearUseCaseOptions {
4
+ import type { IResetUseCase } from '../../core/interfaces/usecase/i-reset-use-case.js';
5
+ export interface ResetUseCaseOptions {
6
6
  contextTreeService: IContextTreeService;
7
7
  contextTreeSnapshotService: IContextTreeSnapshotService;
8
8
  terminal: ITerminal;
9
9
  }
10
- export declare class ClearUseCase implements IClearUseCase {
10
+ export declare class ResetUseCase implements IResetUseCase {
11
11
  private readonly contextTreeService;
12
12
  private readonly contextTreeSnapshotService;
13
13
  private readonly terminal;
14
- constructor(options: ClearUseCaseOptions);
15
- protected confirmClear(): Promise<boolean>;
14
+ constructor(options: ResetUseCaseOptions);
15
+ protected confirmReset(): Promise<boolean>;
16
16
  run(options: {
17
17
  directory?: string;
18
18
  skipConfirmation: boolean;
@@ -1,7 +1,7 @@
1
1
  import { rm } from 'node:fs/promises';
2
2
  import { join } from 'node:path';
3
3
  import { BRV_DIR, CONTEXT_TREE_DIR } from '../../constants.js';
4
- export class ClearUseCase {
4
+ export class ResetUseCase {
5
5
  contextTreeService;
6
6
  contextTreeSnapshotService;
7
7
  terminal;
@@ -11,10 +11,10 @@ export class ClearUseCase {
11
11
  this.terminal = options.terminal;
12
12
  }
13
13
  // Protected method for testability - can be overridden in tests
14
- async confirmClear() {
14
+ async confirmReset() {
15
15
  return this.terminal.confirm({
16
16
  default: false,
17
- message: 'Are you sure you want to reset the context tree? This will remove all existing context and restore default domains.',
17
+ message: 'Are you sure you want to reset the context tree? This will remove all existing context and restore default domains',
18
18
  });
19
19
  }
20
20
  async run(options) {
@@ -22,12 +22,12 @@ export class ClearUseCase {
22
22
  // Check if context tree exists
23
23
  const exists = await this.contextTreeService.exists(options.directory);
24
24
  if (!exists) {
25
- this.terminal.log('No context tree found. Nothing to clear.');
25
+ this.terminal.log('No context tree found. Nothing to reset.');
26
26
  return;
27
27
  }
28
28
  // Confirmation prompt (unless skipConfirmation is true)
29
29
  if (!options.skipConfirmation) {
30
- const confirmed = await this.confirmClear();
30
+ const confirmed = await this.confirmReset();
31
31
  if (!confirmed) {
32
32
  this.terminal.log('Cancelled. Context tree was not reset.');
33
33
  return;
@@ -10,8 +10,8 @@ prompt: |
10
10
  - the domains of the context (dynamically created based on content)
11
11
  - the topics of the context
12
12
  - the subtopics of the context (maximum one level under topics)
13
- - the code snippets of the context
14
- - the content of the context
13
+ - the structured metadata (Raw Concept) and descriptive context (Narrative)
14
+ - the code snippets of the context (optional, for backward compatibility)
15
15
 
16
16
  For doing that, you will need to acquire information from the chat history with the corresponding tools. Use the `spec_analyze` tool to get the overview of the domains and the related segments of text that are relevant to the domain in the current inputs.
17
17
 
@@ -31,6 +31,8 @@ prompt: |
31
31
  Use the `curate` tool to create new knowledge topics or update existing ones. Ensure that:
32
32
  - **Dynamic Domain Creation**: Create domains that are semantically meaningful for the content being curated
33
33
  - The context is well-structured and MUST meet **Context quality requirements**
34
+ - **Domain selection**: Always prefer predefined domains (code_style, design, structure, compliance, testing, bug_fixes). Only create custom domains if content clearly doesn't fit any predefined domain. Maximum 3 custom domains allowed.
35
+ - The context is well-structured and MUST use the **Two-Part Context Model**
34
36
  - There is no duplication with existing context
35
37
  - The information is clear and easy to understand
36
38
 
@@ -43,22 +45,71 @@ prompt: |
43
45
  - **Before creating a new domain**: Check if existing domains could accommodate the content
44
46
  - **Consolidate related concepts**: Group similar topics under the same domain for better organization
45
47
 
46
- 5. **Tool Execution Efficiency:**
47
- - When multiple tools don't depend on each other's results, execute them in parallel with `batch`
48
- - Example: `glob_files`, `list_directory`, `grep_content` and `read_file` operations for different files can run together
48
+ 5. **Two-Part Context Model (REQUIRED)**: When creating context using the `curate` tool, you MUST use the structured format with `rawConcept` and `narrative`:
49
+
50
+ **rawConcept** - Captures essential metadata and technical footprint:
51
+ - `task`: What is the task/feature being documented (required - always include this)
52
+ - `changes`: Array of changes induced in the codebase (e.g., ["Added Redis caching", "Created singleton client"])
53
+ - `files`: Array of related files (e.g., ["services/auth.ts", "utils/cache.ts"])
54
+ - `flow`: The execution flow (e.g., "request -> validate -> cache check -> process -> respond")
55
+ - `timestamp`: When created (ISO 8601 format, e.g., "2025-03-18")
56
+
57
+ **narrative** - Captures descriptive and structural context:
58
+ - `structure`: Code structure documentation (describe file organization, class hierarchy, etc.)
59
+ - `dependencies`: Dependency management information (external libs, internal dependencies, initialization order)
60
+ - `features`: Feature documentation (behavior, limitations, edge cases, caching TTLs, etc.)
49
61
 
50
- 6. **Context quality requirements**: Each context in the `contexts` array must:
51
- - Important: Minimum 2-4 sentences per context. Otherwise, DO NOT add that context.
52
- - A developer should understand the concept without reading source code
62
+ **Example curate tool call:**
63
+ ```json
64
+ {
65
+ "type": "ADD",
66
+ "path": "structure/authentication",
67
+ "title": "JWT Token Handling",
68
+ "content": {
69
+ "rawConcept": {
70
+ "task": "Implement JWT-based authentication with refresh tokens",
71
+ "changes": [
72
+ "Added JWT verification middleware",
73
+ "Implemented refresh token rotation",
74
+ "Added token blacklist using Redis"
75
+ ],
76
+ "files": [
77
+ "src/middleware/auth.ts",
78
+ "src/services/token-service.ts",
79
+ "src/utils/jwt.ts"
80
+ ],
81
+ "flow": "request -> extract token -> verify JWT -> check blacklist -> attach user -> proceed",
82
+ "timestamp": "2025-01-02"
83
+ },
84
+ "narrative": {
85
+ "structure": "Authentication is handled by middleware in src/middleware/auth.ts which delegates to TokenService for JWT operations",
86
+ "dependencies": "Uses jsonwebtoken library for JWT operations, Redis for token blacklist with 24h TTL",
87
+ "features": "Access tokens expire in 15 minutes, refresh tokens in 7 days. Refresh token rotation invalidates old tokens immediately"
88
+ },
89
+ "relations": ["@structure/redis", "@design/security"]
90
+ },
91
+ "reason": "Documenting new JWT authentication system"
92
+ }
93
+ ```
94
+
95
+ 6. **Context Quality Requirements**: Each context MUST:
96
+ - Include a clear `task` in rawConcept describing what the concept is about
97
+ - Provide at least one of: `changes`, `files`, or `flow` in rawConcept
98
+ - Include at least one narrative field (`structure`, `dependencies`, or `features`)
99
+ - Contain minimum 2-4 sentences per context - otherwise, DO NOT add that context
100
+ - Ensure a developer can understand the concept without reading source code
53
101
  - Include names of functions, classes, patterns, or key concepts
54
102
 
55
- AVOID vague contexts like:
103
+ **AVOID** vague contexts like:
56
104
  - "Hook system"
57
105
  - "Error handling"
106
+ - Only snippets without rawConcept/narrative
107
+ - Missing task description
108
+ - Vague single-word descriptions
58
109
 
59
- WRITE detailed contexts like:
110
+ **WRITE** detailed contexts like:
60
111
  - "The hook system allows registering callbacks for lifecycle events. Register hooks using
61
- `HookRegistry.register(hookName, callback)` and trigger them with `HookRegistry.trigger(hookName, context)`. Hooks are used to:
112
+ `HookRegistry.register(hookName, callback)` and trigger them with `HookRegistry.trigger(hookName, context)`. Hooks
62
113
  support async callbacks and are commonly used for: pre/post tool execution, agent lifecycle events, and custom
63
114
  integrations."
64
115
 
@@ -66,7 +117,11 @@ prompt: |
66
117
  code, message, context object, and optional cause. Use `ErrorHandler.wrap(fn)` for consistent error boundaries across
67
118
  async operations."
68
119
 
69
- 7. **Response Format**:
120
+ 7. **Tool Execution Efficiency**:
121
+ - When multiple tools don't depend on each other's results, execute them in parallel with `batch`
122
+ - Example: `glob_files`, `list_directory`, `grep_content` and `read_file` operations for different files can run together
123
+
124
+ 8. **Response Format**:
70
125
  - Your final response must be a brief summary (1-2 sentences) describing what knowledge was curated
71
126
  - Do NOT include any file paths, directory paths, or specific location details in your response
72
- - The system will automatically display created/updated file paths in a separate section
127
+ - The system will automatically display created/updated file paths in a separate section