praana 0.5.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.
Files changed (204) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +124 -0
  3. package/bin/praana.js +17 -0
  4. package/bin/pran.js +17 -0
  5. package/dist/app-banner.d.ts +11 -0
  6. package/dist/app-banner.js +161 -0
  7. package/dist/app-controller.d.ts +44 -0
  8. package/dist/app-controller.js +143 -0
  9. package/dist/app-identity.d.ts +18 -0
  10. package/dist/app-identity.js +52 -0
  11. package/dist/auto-compact.d.ts +16 -0
  12. package/dist/auto-compact.js +101 -0
  13. package/dist/cli-args.d.ts +14 -0
  14. package/dist/cli-args.js +69 -0
  15. package/dist/compile-classic.d.ts +21 -0
  16. package/dist/compile-classic.js +106 -0
  17. package/dist/compiler.d.ts +75 -0
  18. package/dist/compiler.js +406 -0
  19. package/dist/config.d.ts +3 -0
  20. package/dist/config.js +433 -0
  21. package/dist/context-engine/activity-log.d.ts +9 -0
  22. package/dist/context-engine/activity-log.js +109 -0
  23. package/dist/context-engine/artifact-store.d.ts +32 -0
  24. package/dist/context-engine/artifact-store.js +272 -0
  25. package/dist/context-engine/bm25.d.ts +3 -0
  26. package/dist/context-engine/bm25.js +32 -0
  27. package/dist/context-engine/checkpoint.d.ts +34 -0
  28. package/dist/context-engine/checkpoint.js +430 -0
  29. package/dist/context-engine/classify.d.ts +3 -0
  30. package/dist/context-engine/classify.js +60 -0
  31. package/dist/context-engine/db.d.ts +73 -0
  32. package/dist/context-engine/db.js +505 -0
  33. package/dist/context-engine/distiller.d.ts +30 -0
  34. package/dist/context-engine/distiller.js +67 -0
  35. package/dist/context-engine/engine-compiler.d.ts +23 -0
  36. package/dist/context-engine/engine-compiler.js +297 -0
  37. package/dist/context-engine/error-tracker.d.ts +21 -0
  38. package/dist/context-engine/error-tracker.js +74 -0
  39. package/dist/context-engine/event-lineage.d.ts +26 -0
  40. package/dist/context-engine/event-lineage.js +120 -0
  41. package/dist/context-engine/extraction.d.ts +26 -0
  42. package/dist/context-engine/extraction.js +83 -0
  43. package/dist/context-engine/index.d.ts +82 -0
  44. package/dist/context-engine/index.js +238 -0
  45. package/dist/context-engine/scoring.d.ts +13 -0
  46. package/dist/context-engine/scoring.js +47 -0
  47. package/dist/context-engine/state-snapshot.d.ts +8 -0
  48. package/dist/context-engine/state-snapshot.js +50 -0
  49. package/dist/context-engine/summarize.d.ts +6 -0
  50. package/dist/context-engine/summarize.js +32 -0
  51. package/dist/context-engine/telemetry.d.ts +25 -0
  52. package/dist/context-engine/telemetry.js +64 -0
  53. package/dist/context-engine/turn-digest.d.ts +50 -0
  54. package/dist/context-engine/turn-digest.js +250 -0
  55. package/dist/context-engine/turn-ledger.d.ts +18 -0
  56. package/dist/context-engine/turn-ledger.js +184 -0
  57. package/dist/context-engine/turn-recorder.d.ts +24 -0
  58. package/dist/context-engine/turn-recorder.js +88 -0
  59. package/dist/context-engine/types.d.ts +201 -0
  60. package/dist/context-engine/types.js +4 -0
  61. package/dist/context-pressure.d.ts +19 -0
  62. package/dist/context-pressure.js +36 -0
  63. package/dist/distillers/generic.d.ts +14 -0
  64. package/dist/distillers/generic.js +93 -0
  65. package/dist/distillers/git-diff.d.ts +8 -0
  66. package/dist/distillers/git-diff.js +119 -0
  67. package/dist/distillers/index.d.ts +2 -0
  68. package/dist/distillers/index.js +16 -0
  69. package/dist/distillers/npm-test.d.ts +8 -0
  70. package/dist/distillers/npm-test.js +50 -0
  71. package/dist/distillers/rg-results.d.ts +8 -0
  72. package/dist/distillers/rg-results.js +28 -0
  73. package/dist/distillers/tsc-errors.d.ts +8 -0
  74. package/dist/distillers/tsc-errors.js +52 -0
  75. package/dist/event-log.d.ts +56 -0
  76. package/dist/event-log.js +214 -0
  77. package/dist/llm.d.ts +29 -0
  78. package/dist/llm.js +155 -0
  79. package/dist/logger.d.ts +94 -0
  80. package/dist/logger.js +287 -0
  81. package/dist/main.d.ts +1 -0
  82. package/dist/main.js +54 -0
  83. package/dist/memory/confidence.d.ts +7 -0
  84. package/dist/memory/confidence.js +37 -0
  85. package/dist/memory/consolidation.d.ts +26 -0
  86. package/dist/memory/consolidation.js +166 -0
  87. package/dist/memory/db.d.ts +40 -0
  88. package/dist/memory/db.js +283 -0
  89. package/dist/memory/dedup.d.ts +6 -0
  90. package/dist/memory/dedup.js +50 -0
  91. package/dist/memory/embedder-factory.d.ts +3 -0
  92. package/dist/memory/embedder-factory.js +81 -0
  93. package/dist/memory/embeddings.d.ts +15 -0
  94. package/dist/memory/embeddings.js +67 -0
  95. package/dist/memory/index.d.ts +9 -0
  96. package/dist/memory/index.js +11 -0
  97. package/dist/memory/ollama-summarizer.d.ts +19 -0
  98. package/dist/memory/ollama-summarizer.js +72 -0
  99. package/dist/memory/openai-summarizer.d.ts +21 -0
  100. package/dist/memory/openai-summarizer.js +51 -0
  101. package/dist/memory/store.d.ts +61 -0
  102. package/dist/memory/store.js +502 -0
  103. package/dist/memory/summarizer-factory.d.ts +3 -0
  104. package/dist/memory/summarizer-factory.js +69 -0
  105. package/dist/memory/summarizer.d.ts +4 -0
  106. package/dist/memory/summarizer.js +112 -0
  107. package/dist/memory/types.d.ts +87 -0
  108. package/dist/memory/types.js +17 -0
  109. package/dist/model-context.d.ts +15 -0
  110. package/dist/model-context.js +212 -0
  111. package/dist/project-detector.d.ts +37 -0
  112. package/dist/project-detector.js +604 -0
  113. package/dist/render.d.ts +15 -0
  114. package/dist/render.js +46 -0
  115. package/dist/session.d.ts +118 -0
  116. package/dist/session.js +809 -0
  117. package/dist/skills/index.d.ts +69 -0
  118. package/dist/skills/index.js +885 -0
  119. package/dist/skills/types.d.ts +93 -0
  120. package/dist/skills/types.js +8 -0
  121. package/dist/slash-commands.d.ts +14 -0
  122. package/dist/slash-commands.js +301 -0
  123. package/dist/state-graph.d.ts +38 -0
  124. package/dist/state-graph.js +255 -0
  125. package/dist/status-bar.d.ts +54 -0
  126. package/dist/status-bar.js +184 -0
  127. package/dist/thinking-display.d.ts +21 -0
  128. package/dist/thinking-display.js +37 -0
  129. package/dist/tool-summary.d.ts +4 -0
  130. package/dist/tool-summary.js +67 -0
  131. package/dist/tools/index.d.ts +925 -0
  132. package/dist/tools/index.js +86 -0
  133. package/dist/tools/knowledge.d.ts +140 -0
  134. package/dist/tools/knowledge.js +260 -0
  135. package/dist/tools/memory.d.ts +39 -0
  136. package/dist/tools/memory.js +300 -0
  137. package/dist/tools/search-code.d.ts +134 -0
  138. package/dist/tools/search-code.js +390 -0
  139. package/dist/tools/system.d.ts +16 -0
  140. package/dist/tools/system.js +499 -0
  141. package/dist/tools/tool-def.d.ts +6 -0
  142. package/dist/tools/tool-def.js +3 -0
  143. package/dist/turn-control.d.ts +51 -0
  144. package/dist/turn-control.js +210 -0
  145. package/dist/turn.d.ts +20 -0
  146. package/dist/turn.js +624 -0
  147. package/dist/types.d.ts +233 -0
  148. package/dist/types.js +4 -0
  149. package/dist/ui/readline-ui.d.ts +2 -0
  150. package/dist/ui/readline-ui.js +176 -0
  151. package/dist/ui/tui/app.d.ts +13 -0
  152. package/dist/ui/tui/app.js +270 -0
  153. package/dist/ui/tui/busy-indicator.d.ts +2 -0
  154. package/dist/ui/tui/busy-indicator.js +13 -0
  155. package/dist/ui/tui/components/gutter-rule.d.ts +5 -0
  156. package/dist/ui/tui/components/gutter-rule.js +9 -0
  157. package/dist/ui/tui/components/inline-tool-row.d.ts +10 -0
  158. package/dist/ui/tui/components/inline-tool-row.js +8 -0
  159. package/dist/ui/tui/components/prompt-input.d.ts +20 -0
  160. package/dist/ui/tui/components/prompt-input.js +120 -0
  161. package/dist/ui/tui/components/system-line.d.ts +5 -0
  162. package/dist/ui/tui/components/system-line.js +6 -0
  163. package/dist/ui/tui/components/thinking-block.d.ts +11 -0
  164. package/dist/ui/tui/components/thinking-block.js +31 -0
  165. package/dist/ui/tui/components/toast-line.d.ts +4 -0
  166. package/dist/ui/tui/components/toast-line.js +8 -0
  167. package/dist/ui/tui/components/tool-result-line.d.ts +5 -0
  168. package/dist/ui/tui/components/tool-result-line.js +6 -0
  169. package/dist/ui/tui/components/turn-footer.d.ts +5 -0
  170. package/dist/ui/tui/components/turn-footer.js +7 -0
  171. package/dist/ui/tui/components/user-block.d.ts +6 -0
  172. package/dist/ui/tui/components/user-block.js +6 -0
  173. package/dist/ui/tui/logo-banner.d.ts +5 -0
  174. package/dist/ui/tui/logo-banner.js +8 -0
  175. package/dist/ui/tui/markdown-render.d.ts +16 -0
  176. package/dist/ui/tui/markdown-render.js +218 -0
  177. package/dist/ui/tui/palette.d.ts +12 -0
  178. package/dist/ui/tui/palette.js +13 -0
  179. package/dist/ui/tui/reasoning-summary.d.ts +12 -0
  180. package/dist/ui/tui/reasoning-summary.js +27 -0
  181. package/dist/ui/tui/reducer.d.ts +92 -0
  182. package/dist/ui/tui/reducer.js +260 -0
  183. package/dist/ui/tui/run.d.ts +3 -0
  184. package/dist/ui/tui/run.js +40 -0
  185. package/dist/ui/tui/sink.d.ts +4 -0
  186. package/dist/ui/tui/sink.js +89 -0
  187. package/dist/ui/tui/status-bar-view.d.ts +5 -0
  188. package/dist/ui/tui/status-bar-view.js +44 -0
  189. package/dist/ui/tui/terminal-height.d.ts +12 -0
  190. package/dist/ui/tui/terminal-height.js +20 -0
  191. package/dist/ui/tui/terminal-width.d.ts +2 -0
  192. package/dist/ui/tui/terminal-width.js +5 -0
  193. package/dist/ui/tui/tool-display.d.ts +23 -0
  194. package/dist/ui/tui/tool-display.js +217 -0
  195. package/dist/ui/tui/transcript-line.d.ts +12 -0
  196. package/dist/ui/tui/transcript-line.js +43 -0
  197. package/dist/ui/tui/transcript-replay.d.ts +12 -0
  198. package/dist/ui/tui/transcript-replay.js +117 -0
  199. package/dist/ui-events.d.ts +39 -0
  200. package/dist/ui-events.js +33 -0
  201. package/dist/ui.d.ts +77 -0
  202. package/dist/ui.js +179 -0
  203. package/package.json +73 -0
  204. package/praana.config.example.toml +231 -0
@@ -0,0 +1,33 @@
1
+ import { printDebug, printDebugBlock, printMemoryBanner, printToolCall, startSpinner, stopSpinner, } from "./ui.js";
2
+ /** Default sink: streaming callbacks + legacy terminal helpers. */
3
+ export function createDefaultTurnSink(options) {
4
+ return {
5
+ onTextDelta: (delta) => {
6
+ if (options?.onTextDelta)
7
+ options.onTextDelta(delta);
8
+ else
9
+ process.stdout.write(delta);
10
+ },
11
+ onThinkingDelta: (delta) => options?.onThinkingDelta?.(delta),
12
+ onToolCallsStart: () => options?.onToolCallsStart?.(),
13
+ onToolCall: (toolName, args) => printToolCall(toolName, args),
14
+ onToolResult: () => {
15
+ /* terminal mode doesn't need a separate result block; it streams naturally */
16
+ },
17
+ onDebug: (message) => printDebug(message),
18
+ onDebugBlock: (stepIndex, toolCalls, toolResults) => printDebugBlock(stepIndex, toolCalls, toolResults),
19
+ onMemoryBanner: (stats) => printMemoryBanner(stats),
20
+ onSpinnerStart: (text) => startSpinner(text),
21
+ onSpinnerStop: () => stopSpinner(),
22
+ onNewline: () => process.stdout.write("\n"),
23
+ onFallback: (text) => process.stdout.write(text + "\n"),
24
+ onError: (entry) => {
25
+ if (entry.level === "error" || entry.level === "warn") {
26
+ process.stderr.write(`[${entry.domain}] ${entry.message}\n`);
27
+ }
28
+ },
29
+ };
30
+ }
31
+ export function hasTurnUiSink(sink) {
32
+ return sink !== undefined;
33
+ }
package/dist/ui.d.ts ADDED
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Terminal UI helpers for ARIA.
3
+ * Tool/status output goes to stderr; stdout gets blank-line breaks so
4
+ * agent text and debug blocks don't run together in the terminal.
5
+ *
6
+ * Color output is managed via chalk (respects NO_COLOR / non-TTY automatically).
7
+ * Spinner (ora) is only activated when stderr is a real TTY.
8
+ *
9
+ * Rich Markdown rendering is provided by marked + marked-terminal.
10
+ * Boxed layouts use boxen.
11
+ */
12
+ type UiWriters = {
13
+ stderr: (line: string) => void;
14
+ breakStdout: () => void;
15
+ };
16
+ export declare function setUiWriters(overrides?: Partial<UiWriters>): void;
17
+ /** Write a line to the UI stderr channel (tool diffs, ancillary output). */
18
+ export declare function writeUiStderr(line: string): void;
19
+ /**
20
+ * Start a spinner on stderr with the given text.
21
+ * No-op when stderr is not a TTY (tests, CI, piped output).
22
+ */
23
+ export declare function startSpinner(text: string): void;
24
+ /**
25
+ * Stop and clear the active spinner.
26
+ * Safe to call when no spinner is running.
27
+ */
28
+ export declare function stopSpinner(): void;
29
+ /**
30
+ * Render content inside a styled box (using boxen).
31
+ * Output goes to stderr.
32
+ */
33
+ export declare function printBox(content: string, options?: {
34
+ title?: string;
35
+ padding?: number;
36
+ borderColor?: "black" | "red" | "green" | "yellow" | "blue" | "magenta" | "cyan" | "white" | "gray";
37
+ }): void;
38
+ /**
39
+ * Render Markdown text to terminal (writes to stderr).
40
+ */
41
+ export declare function printMarkdown(text: string): void;
42
+ /** Compact tool indicator — shown in normal mode. */
43
+ export declare function printToolCall(toolName: string, args: Record<string, unknown>): void;
44
+ /**
45
+ * Render a complete debug block with all tool calls and results in a single
46
+ * styled box (using boxen). This is the preferred debug display — replaces
47
+ * the manual start/content/end sequence for a polished look.
48
+ */
49
+ export declare function printDebugBlock(stepIndex: number, toolCalls: Array<{
50
+ toolName: string;
51
+ args: Record<string, unknown>;
52
+ }>, toolResults: Array<{
53
+ toolName: string;
54
+ result: unknown;
55
+ }>): void;
56
+ /** Debug block header before a batch of tool calls in a step. */
57
+ export declare function printToolBlockStart(stepIndex: number): void;
58
+ /** Debug tool call with full args. */
59
+ export declare function printToolCallDebug(toolName: string, args: Record<string, unknown>): void;
60
+ /** Debug tool result. */
61
+ export declare function printToolResultDebug(toolName: string, result: unknown): void;
62
+ /** Debug block footer. */
63
+ export declare function printToolBlockEnd(): void;
64
+ /** General debug message (prompt saved, etc.). */
65
+ export declare function printDebug(message: string): void;
66
+ /** Compact per-turn memory banner after each response. */
67
+ export declare function printMemoryBanner(stats: {
68
+ activeState: number;
69
+ totalState: number;
70
+ digestLen: number;
71
+ recallCalls: number;
72
+ recallHits: number;
73
+ autoHydrated: number;
74
+ promptTokens: number;
75
+ outputTokens: number;
76
+ }): void;
77
+ export {};
package/dist/ui.js ADDED
@@ -0,0 +1,179 @@
1
+ /**
2
+ * Terminal UI helpers for ARIA.
3
+ * Tool/status output goes to stderr; stdout gets blank-line breaks so
4
+ * agent text and debug blocks don't run together in the terminal.
5
+ *
6
+ * Color output is managed via chalk (respects NO_COLOR / non-TTY automatically).
7
+ * Spinner (ora) is only activated when stderr is a real TTY.
8
+ *
9
+ * Rich Markdown rendering is provided by marked + marked-terminal.
10
+ * Boxed layouts use boxen.
11
+ */
12
+ import chalk from "chalk";
13
+ import ora from "ora";
14
+ import boxen from "boxen";
15
+ import { renderMarkdown } from "./render.js";
16
+ import { summarizeArgs, summarizeResult } from "./tool-summary.js";
17
+ const defaultWriters = {
18
+ stderr: (line) => process.stderr.write(line),
19
+ breakStdout: () => process.stdout.write("\n"),
20
+ };
21
+ let writers = defaultWriters;
22
+ let activeSpinner = null;
23
+ function stderr(line) {
24
+ writers.stderr(line);
25
+ }
26
+ /** Break the agent text flow on stdout before/after ancillary output. */
27
+ function breakStdout() {
28
+ writers.breakStdout();
29
+ }
30
+ export function setUiWriters(overrides) {
31
+ if (!overrides) {
32
+ writers = defaultWriters;
33
+ return;
34
+ }
35
+ writers = {
36
+ stderr: overrides.stderr ?? defaultWriters.stderr,
37
+ breakStdout: overrides.breakStdout ?? defaultWriters.breakStdout,
38
+ };
39
+ }
40
+ /** Write a line to the UI stderr channel (tool diffs, ancillary output). */
41
+ export function writeUiStderr(line) {
42
+ writers.stderr(line.endsWith("\n") ? line : line + "\n");
43
+ }
44
+ /**
45
+ * Start a spinner on stderr with the given text.
46
+ * No-op when stderr is not a TTY (tests, CI, piped output).
47
+ */
48
+ export function startSpinner(text) {
49
+ if (!process.stderr.isTTY)
50
+ return;
51
+ stopSpinner();
52
+ activeSpinner = ora({ text, stream: process.stderr, discardStdin: false }).start();
53
+ }
54
+ /**
55
+ * Stop and clear the active spinner.
56
+ * Safe to call when no spinner is running.
57
+ */
58
+ export function stopSpinner() {
59
+ if (!activeSpinner)
60
+ return;
61
+ activeSpinner.stop();
62
+ activeSpinner = null;
63
+ }
64
+ /**
65
+ * Render content inside a styled box (using boxen).
66
+ * Output goes to stderr.
67
+ */
68
+ export function printBox(content, options) {
69
+ if (!content)
70
+ return;
71
+ const opts = {
72
+ padding: options?.padding ?? 1,
73
+ margin: 0,
74
+ borderStyle: "round",
75
+ title: options?.title,
76
+ titleAlignment: "left",
77
+ ...(options?.borderColor ? { borderColor: options.borderColor } : {}),
78
+ };
79
+ stderr(boxen(content, opts) + "\n");
80
+ }
81
+ /**
82
+ * Render Markdown text to terminal (writes to stderr).
83
+ */
84
+ export function printMarkdown(text) {
85
+ if (!text)
86
+ return;
87
+ const rendered = renderMarkdown(text);
88
+ stderr(rendered);
89
+ if (!rendered.endsWith("\n"))
90
+ stderr("\n");
91
+ }
92
+ /** Compact tool indicator — shown in normal mode. */
93
+ export function printToolCall(toolName, args) {
94
+ breakStdout();
95
+ const summary = summarizeArgs(toolName, args);
96
+ stderr(`\n${chalk.dim("[tool]")} ${chalk.cyan(toolName)}${summary ? ` ${chalk.dim(`:: ${summary}`)}` : ""}\n`);
97
+ breakStdout();
98
+ }
99
+ /**
100
+ * Render a complete debug block with all tool calls and results in a single
101
+ * styled box (using boxen). This is the preferred debug display — replaces
102
+ * the manual start/content/end sequence for a polished look.
103
+ */
104
+ export function printDebugBlock(stepIndex, toolCalls, toolResults) {
105
+ breakStdout();
106
+ const lines = [];
107
+ for (const tc of toolCalls) {
108
+ const argsJson = JSON.stringify(tc.args);
109
+ const display = argsJson.length > 200 ? argsJson.slice(0, 197) + "..." : argsJson;
110
+ lines.push(`${chalk.yellow("▸")} ${chalk.cyan(tc.toolName)}(${chalk.dim(display)})`);
111
+ }
112
+ for (const tr of toolResults) {
113
+ const summary = summarizeResult(tr.result);
114
+ lines.push(` ${chalk.green("◂")} ${chalk.cyan(tr.toolName)} ${chalk.dim(summary)}`);
115
+ }
116
+ if (lines.length === 0)
117
+ return;
118
+ stderr(boxen(lines.join("\n"), {
119
+ padding: { top: 0, bottom: 0, left: 1, right: 1 },
120
+ margin: 0,
121
+ borderStyle: "round",
122
+ borderColor: "yellow",
123
+ title: `step ${stepIndex} tools`,
124
+ titleAlignment: "left",
125
+ }) + "\n");
126
+ breakStdout();
127
+ }
128
+ /** Debug block header before a batch of tool calls in a step. */
129
+ export function printToolBlockStart(stepIndex) {
130
+ breakStdout();
131
+ stderr(`\n${chalk.yellow("[debug]")} ${chalk.dim(`┌ step ${stepIndex} tool execution ${"─".repeat(18)}┐`)}\n`);
132
+ }
133
+ /** Debug tool call with full args. */
134
+ export function printToolCallDebug(toolName, args) {
135
+ const argsJson = JSON.stringify(args);
136
+ const display = argsJson.length > 200 ? argsJson.slice(0, 197) + "..." : argsJson;
137
+ stderr(` ${chalk.yellow(">")} ${toolName}(${display})\n`);
138
+ }
139
+ /** Debug tool result. */
140
+ export function printToolResultDebug(toolName, result) {
141
+ const summary = summarizeResult(result);
142
+ stderr(` ${chalk.green("<")} ${toolName} ${chalk.dim(summary)}\n`);
143
+ }
144
+ /** Debug block footer. */
145
+ export function printToolBlockEnd() {
146
+ stderr(`${chalk.dim(`└${"─".repeat(46)}┘`)}\n`);
147
+ breakStdout();
148
+ }
149
+ /** General debug message (prompt saved, etc.). */
150
+ export function printDebug(message) {
151
+ stderr(`\n${chalk.yellow("[debug]")} ${message}\n`);
152
+ breakStdout();
153
+ }
154
+ /** Compact per-turn memory banner after each response. */
155
+ export function printMemoryBanner(stats) {
156
+ if (stats.activeState === 0 &&
157
+ stats.recallCalls === 0 &&
158
+ stats.autoHydrated === 0 &&
159
+ stats.digestLen === 0 &&
160
+ !stats.promptTokens &&
161
+ !stats.outputTokens)
162
+ return;
163
+ const parts = [];
164
+ if (stats.activeState > 0 || stats.totalState > 0)
165
+ parts.push(`${stats.activeState}/${stats.totalState} state`);
166
+ if (stats.digestLen > 0)
167
+ parts.push(`digest ${stats.digestLen}c`);
168
+ if (stats.recallCalls > 0)
169
+ parts.push(`recall ${stats.recallHits}h`);
170
+ if (stats.autoHydrated > 0)
171
+ parts.push(`auto+${stats.autoHydrated}`);
172
+ if (stats.promptTokens && stats.promptTokens > 0)
173
+ parts.push(`prompt ~${stats.promptTokens}t`);
174
+ if (stats.outputTokens && stats.outputTokens > 0)
175
+ parts.push(`out ~${stats.outputTokens}t`);
176
+ if (parts.length === 0)
177
+ return;
178
+ stderr(`\n${chalk.dim(`[state] ${parts.join(" | ")}`)}\n`);
179
+ }
package/package.json ADDED
@@ -0,0 +1,73 @@
1
+ {
2
+ "name": "praana",
3
+ "version": "0.5.0",
4
+ "description": "Terminal coding agent with adaptive context and cross-session memory",
5
+ "license": "MIT",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/amitkumardubey/praana.git"
9
+ },
10
+ "keywords": [
11
+ "cli",
12
+ "ai",
13
+ "coding-agent",
14
+ "terminal",
15
+ "assistant",
16
+ "llm"
17
+ ],
18
+ "type": "module",
19
+ "bin": {
20
+ "praana": "bin/praana.js",
21
+ "pran": "bin/pran.js"
22
+ },
23
+ "files": [
24
+ "bin",
25
+ "dist",
26
+ "praana.config.example.toml"
27
+ ],
28
+ "engines": {
29
+ "node": ">=22"
30
+ },
31
+ "scripts": {
32
+ "build": "tsc",
33
+ "prepublishOnly": "rm -rf dist && tsc",
34
+ "start": "node dist/main.js",
35
+ "dev": "tsx src/main.ts",
36
+ "test": "vitest run",
37
+ "test:watch": "vitest",
38
+ "test:coverage": "vitest run --coverage"
39
+ },
40
+ "dependencies": {
41
+ "@earendil-works/pi-ai": "^0.75.5",
42
+ "better-sqlite3": "^11.0.0",
43
+ "boxen": "^8.0.1",
44
+ "chalk": "^5.6.2",
45
+ "cli-highlight": "^2.1.11",
46
+ "cliui": "^9.0.1",
47
+ "ink": "^7.0.5",
48
+ "ink-text-input": "^6.0.0",
49
+ "js-yaml": "^4.2.0",
50
+ "marked": "^15.0.12",
51
+ "marked-terminal": "^7.3.0",
52
+ "ora": "^9.4.0",
53
+ "pino": "^10.3.1",
54
+ "pino-pretty": "^13.1.3",
55
+ "pino-roll": "^4.0.0",
56
+ "react": "^19.2.7",
57
+ "sqlite-vec": "^0.1.6",
58
+ "strip-ansi": "^7.2.0",
59
+ "toml": "^3.0.0",
60
+ "ulid": "^2.3.0",
61
+ "zod": "^3.23.0",
62
+ "zod-to-json-schema": "^3.25.2"
63
+ },
64
+ "devDependencies": {
65
+ "@types/better-sqlite3": "^7.6.0",
66
+ "@types/js-yaml": "^4.0.9",
67
+ "@types/node": "^22.0.0",
68
+ "@types/react": "^19.2.17",
69
+ "tsx": "^4.16.0",
70
+ "typescript": "^5.5.0",
71
+ "vitest": "^4.1.7"
72
+ }
73
+ }
@@ -0,0 +1,231 @@
1
+ # PRAANA Configuration — Example
2
+ #
3
+ # Copy this file to `praana.config.toml` in your project root and customize:
4
+ # cp praana.config.example.toml praana.config.toml
5
+ #
6
+ # All values shown are the built-in defaults. You only need to
7
+ # override what you want to change. PRAANA works with zero config.
8
+ #
9
+ # Config is loaded from (later overrides earlier):
10
+ # 1. ~/.praana/praana.config.json
11
+ # 2. ~/.praana/config.toml
12
+ # 3. ./praana.config.json
13
+ # 4. ./praana.config.toml
14
+
15
+ [llm]
16
+ # LLM provider. Supported values:
17
+ # openrouter — OpenRouter (default). Works with 200+ models from any provider.
18
+ # openai — OpenAI API (gpt-4o, o3, etc.)
19
+ # anthropic — Anthropic API (claude-sonnet-4, claude-3.5, etc.)
20
+ # google — Google Gemini API (gemini-2.5-flash, gemini-2.5-pro)
21
+ # deepseek — DeepSeek API (deepseek-v4-pro, deepseek-chat)
22
+ # groq — Groq API (fast inference on open models)
23
+ # mistral — Mistral AI API
24
+ # xai — xAI API (grok)
25
+ # fireworks — Fireworks AI
26
+ # together — Together AI
27
+ # ollama — Local Ollama (no API key needed)
28
+ # opencode — OpenCode Zen (big-pickle, minimax-m2.5, etc.)
29
+ # amazon-bedrock — AWS Bedrock (uses AWS credentials, not an API key)
30
+ provider = "openrouter"
31
+
32
+ # Model name passed to the provider.
33
+ # For OpenRouter: use "provider/model" format, e.g. "deepseek/deepseek-v4-pro"
34
+ # For native providers: use the model name directly, e.g. "claude-sonnet-4-20250514"
35
+ # Override at runtime via PRAANA_MODEL env var (legacy: ARIA_MODEL) or /model command.
36
+ model = "deepseek/deepseek-v4-flash:free"
37
+
38
+ # Optional: override detected model context window (input tokens) for pressure and compaction
39
+ # context_window = 128000
40
+
41
+ # Free tier — zero cost, good for getting started.
42
+ # Upgrade to a paid model for better results on complex tasks:
43
+ # deepseek/deepseek-v4-pro
44
+ # anthropic/claude-sonnet-4-5
45
+ # openai/gpt-4o
46
+
47
+ # Optional: Custom API base URL (e.g., for self-hosted or proxy)
48
+ # base_url = "https://my-proxy.example.com/v1"
49
+
50
+ # API keys are read from environment variables:
51
+ # openrouter → OPENROUTER_API_KEY
52
+ # openai → OPENAI_API_KEY
53
+ # anthropic → ANTHROPIC_API_KEY
54
+ # google → GOOGLE_GENERATIVE_AI_API_KEY
55
+ # deepseek → DEEPSEEK_API_KEY
56
+ # groq → GROQ_API_KEY
57
+ # mistral → MISTRAL_API_KEY
58
+ # xai → XAI_API_KEY
59
+ # fireworks → FIREWORKS_API_KEY
60
+ # together → TOGETHER_API_KEY
61
+ # ollama → (none — runs locally)
62
+ # opencode → OPENCODE_API_KEY (from https://opencode.ai/auth)
63
+ # amazon-bedrock → (none — uses AWS credentials chain)
64
+
65
+ [memory]
66
+ # Enable/disable Cognitive Memory (SQLite-backed cross-session persistence)
67
+ enabled = true
68
+
69
+ # Session-end learning extraction (runs on /exit):
70
+ # disabled — no LLM call; no cross-session learnings saved
71
+ # ollama — local Ollama chat API (no API key; see ollama_* below)
72
+ # openrouter — OpenRouter (OPENROUTER_API_KEY)
73
+ # openai — OpenAI API (OPENAI_API_KEY)
74
+ summarizer = "openrouter"
75
+
76
+ # Path to the SQLite memory database (~ is expanded to $HOME)
77
+ db_path = "~/.praana/memory.db"
78
+
79
+ # --- Embeddings (semantic /recall) ---
80
+ # auto — try Ollama, fall back to hash with a warning
81
+ # ollama — require Ollama (fall back to hash if unavailable)
82
+ # transformers — @huggingface/transformers (npm install, ~266MB)
83
+ # llama-cpp — node-llama-cpp (native, requires build tools)
84
+ # hash — deterministic offline vectors (non-semantic)
85
+ embedder = "auto"
86
+
87
+ # Ollama daemon URL (embeddings + summarizer when summarizer = "ollama")
88
+ ollama_url = "http://localhost:11434"
89
+
90
+ # Embedding model — must be installed: `ollama pull nomic-embed-text`
91
+ ollama_model = "nomic-embed-text"
92
+
93
+ # Chat model for summarizer = "ollama" (session-end learnings).
94
+ # Must be a chat model from `ollama list`, not an embedding model.
95
+ # Ways to set it (pick one):
96
+ # 1. ollama_summarizer_model below (recommended)
97
+ # 2. PRAANA_SUMMARIZER_MODEL env var (e.g. export PRAANA_SUMMARIZER_MODEL=qwen3.5:4b)
98
+ # 3. Leave unset — auto-picks the first non-embedding model from `ollama list`
99
+ # ollama_summarizer_model = "qwen3.5:4b"
100
+
101
+ # --- Example: fully local memory (no OpenRouter for summarizer) ---
102
+ # summarizer = "ollama"
103
+ # embedder = "ollama"
104
+ # ollama_url = "http://localhost:11434"
105
+ # ollama_model = "nomic-embed-text"
106
+ # ollama_summarizer_model = "qwen3.5:4b"
107
+
108
+ # Summarizer model override for openrouter/openai (ignored when summarizer = "ollama"):
109
+ # export PRAANA_SUMMARIZER_MODEL=google/gemini-2.5-flash
110
+
111
+ [compiler]
112
+ # Total estimated token budget for the compiled prompt
113
+ token_budget = 100000
114
+
115
+ # Number of recent user/agent turns to include in context
116
+ recent_turns = 10
117
+
118
+ # Token budget reserved specifically for the Recent Turns section
119
+ recent_turns_token_budget = 30000
120
+
121
+ # Max share of token_budget for AGENTS.md / project context in the system frame
122
+ agents_budget_ratio = 0.3
123
+
124
+ # Tokens reserved for model output when measuring context pressure
125
+ # reserved_output_tokens = 0
126
+
127
+ # Auto-compact when prompt fill reaches this ratio of the model context window (classic mode)
128
+ auto_compact_at = 0.75
129
+
130
+ # Disarm compaction hysteresis below this ratio (classic mode)
131
+ auto_compact_clear_at = 0.55
132
+
133
+ # Fraction of oldest transcript events to summarise per compaction (classic mode)
134
+ compact_chunk_fraction = 0.25
135
+
136
+ # Classic mode: never auto-compact (full verbatim until model limit)
137
+ # verbatim_only = false
138
+
139
+ [skills]
140
+ # Discover and load SKILL.md files (https://agentskills.io/)
141
+ enabled = true
142
+
143
+ # Max share of token_budget for the skills section in the compiled prompt
144
+ max_token_budget_ratio = 0.2
145
+
146
+ # Residency: hot skills demote to warm after this many idle turns
147
+ active_skill_idle_turns = 5
148
+
149
+ # Warm skills evict to cold after this many idle turns
150
+ warm_skill_eviction_turns = 20
151
+
152
+ # Max directory depth when scanning skill search paths
153
+ max_depth = 6
154
+
155
+ [tiers]
156
+ # Turns of inactivity before active → soft tier demotion
157
+ idle_soft_after_turns = 20
158
+
159
+ # Turns of inactivity before active/soft → hard tier demotion
160
+ idle_hard_after_turns = 50
161
+
162
+ [session]
163
+ # Directory where session event logs are stored
164
+ log_dir = "~/.praana/sessions"
165
+
166
+ [search_code]
167
+ # Optional: absolute path to the ripgrep binary.
168
+ # Leave unset to resolve "rg" from $PATH (default).
169
+ # Useful when ripgrep is installed outside PATH (e.g. a vendored copy).
170
+ # rg_path = "/opt/homebrew/bin/rg"
171
+
172
+ [context_engine]
173
+ # Context engine: structured checkpoint, distillation, and scored compilation.
174
+ # When disabled (false), PRAANA runs in classic mode — full verbatim conversation
175
+ # history, no StateGraph tools, skills loaded as metadata catalog only.
176
+ # If enabled but initialization fails, PRAANA falls back to the same classic mode.
177
+ #
178
+ # When enabled, SessionCheckpoint is reconciled after every turn from a
179
+ # deterministic TurnDigest (never by the LLM). Checkpoint sections:
180
+ # - Active request (latest user intent)
181
+ # - Session narrative (rolling prose from digest data, max 20 entries)
182
+ # - Plan (current + superseded plans with completion hints)
183
+ # - Constraints (append-only, never dropped)
184
+ # - Decisions (rationale retained even after age-based compaction)
185
+ # - Files in play, findings, errors, recent activity
186
+ # Casual user preferences ("we use pnpm", "let's use JWT") are NOT captured by regex —
187
+ # the system prompt nudge directs the LLM to call add_constraint for those.
188
+ # Only the unambiguous "not X, Y" correction pattern is regex-captured.
189
+ enabled = false
190
+
191
+ # Write telemetry even when engine is off (debug / comparison during development)
192
+ measurement_mode = false
193
+
194
+ # Tool outputs at or below this token count appear verbatim in the prompt
195
+ artifact_inline_threshold = 400
196
+
197
+ # Turns without access before an artifact is eligible for eviction
198
+ artifact_ttl_turns = 50
199
+
200
+ # Enable structured SessionCheckpoint in the prompt (see section list above).
201
+ # Section token budgets are fixed in code: narrative/plan 400 each, decisions 800,
202
+ # findings 300. No per-section config yet.
203
+ checkpoint_enabled = true
204
+
205
+ # Use LLM for ambiguous userIntent extraction (default: first 120 chars)
206
+ llm_digest = false
207
+
208
+ # Max rolling activity entries kept for checkpoint preview
209
+ activity_log_max_entries = 15
210
+
211
+ [context_engine.distiller]
212
+ # Distiller compression intensity: "lite" (conservative) or "full" (aggressive)
213
+ default_intensity = "full"
214
+
215
+ [context_engine.scoring]
216
+ # Scoring weights for context unit selection (3-term model: pin + recency + relevance)
217
+ w_pin = 1.0
218
+ w_recency = 0.5
219
+ w_relevance = 0.3
220
+
221
+ [context_engine.pressure]
222
+ # Prompt pressure ratio triggers compaction
223
+ compact_at = 0.70
224
+ # Emergency: drop all turn digests, keep checkpoint + verbatim last 2 turns
225
+ emergency_at = 0.85
226
+
227
+ [ui]
228
+ # Terminal interface: "tui" (Ink chat shell) or "readline" (classic CLI)
229
+ mode = "tui"
230
+ # Screen mode for TUI: "preserve" keeps scrollback (default), "alternate" uses full-screen buffer
231
+ screen = "preserve"