kritya 0.8.26-beta → 0.8.27-beta

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.
@@ -1,38 +1,12 @@
1
- import { wrapInline } from "./inline.js";
2
- /** Rows below the streaming region: prompt, status line, spinner, breathing room. */
1
+ /**
2
+ * Rows the live region below the streaming answer needs: the prompt box, the
3
+ * spinner and steer input, the status line, and a little breathing room. The
4
+ * live answer is clipped to what is left, so the prompt stays on screen while
5
+ * it streams.
6
+ */
3
7
  const RESERVED_ROWS = 8;
4
8
  /** Never collapse the live view to nothing, however short the terminal. */
5
9
  const MIN_ROWS = 4;
6
- /**
7
- * Rows held back against an estimate that comes in low. Underestimating by
8
- * even one row brings back the bug this file exists to prevent, and the only
9
- * cost of overestimating is showing slightly less of the live text.
10
- */
11
- const SAFETY_ROWS = 4;
12
- /** Columns the renderer itself works in: the terminal, less its padding. */
13
- const RENDER_INSET = 2;
14
- /** A table row wraps its cells; assume the worst rather than guess low. */
15
- const TABLE_ROW_HEIGHT = 3;
16
- /**
17
- * Terminal rows a line will occupy once rendered. Measured with the same
18
- * word-wrapping the renderer uses — dividing width by columns assumes words
19
- * can be split mid-word, which under-counts every wrapped paragraph.
20
- */
21
- function rowsFor(line, columns) {
22
- const width = Math.max(1, columns - RENDER_INSET);
23
- const wrapped = wrapInline(line, width).length;
24
- return line.includes("|") ? Math.max(wrapped, TABLE_ROW_HEIGHT) : Math.max(1, wrapped);
25
- }
26
- /**
27
- * The tail of a streaming answer that fits the viewport.
28
- *
29
- * Ink erases its live region by rewinding a line count, which can only reach
30
- * what is still on screen. Let the streaming text grow past the terminal's
31
- * height and the erase silently comes up short, stranding a partial copy in
32
- * the scrollback — then the finished message prints below it and the answer
33
- * appears twice. Showing only what fits keeps the erase exact; the whole
34
- * answer is printed once when the turn ends.
35
- */
36
10
  /**
37
11
  * The terminal's size, falling back to 80x24 when it isn't known.
38
12
  *
@@ -50,22 +24,15 @@ export function terminalColumns(stdout) {
50
24
  export function terminalRows(stdout) {
51
25
  return stdout?.rows || 24;
52
26
  }
53
- export function tailForViewport(text, columns, rows) {
54
- const budget = Math.max(MIN_ROWS, rows - RESERVED_ROWS - SAFETY_ROWS);
55
- const lines = text.split("\n");
56
- let used = 0;
57
- let start = lines.length;
58
- while (start > 0) {
59
- const next = used + rowsFor(lines[start - 1], columns);
60
- if (next > budget)
61
- break;
62
- used = next;
63
- start--;
64
- }
65
- if (start === 0)
66
- return text;
67
- const tail = lines.slice(start);
68
- // Reopen a fence the cut landed inside, so the tail doesn't render as prose.
69
- const fencesDropped = lines.slice(0, start).filter((l) => l.trimStart().startsWith("```")).length;
70
- return fencesDropped % 2 === 1 ? `\`\`\`\n${tail.join("\n")}` : tail.join("\n");
27
+ /**
28
+ * Rows the streaming answer may occupy: the terminal, less the live region
29
+ * that has to stay visible below it.
30
+ *
31
+ * This used to be the budget for slicing the answer by hand — wrapping every
32
+ * line to estimate the rows it would render at, then keeping the tail that
33
+ * fit. Ink 8 clips a `<Box>` natively (see StreamViewport.tsx), so the only
34
+ * thing left to decide is how much room the live region gets.
35
+ */
36
+ export function streamRows(rows) {
37
+ return Math.max(MIN_ROWS, rows - RESERVED_ROWS);
71
38
  }
package/dist/undo/undo.js CHANGED
@@ -25,6 +25,8 @@ export class UndoStack {
25
25
  entries = [];
26
26
  redoStack = [];
27
27
  turn = 0;
28
+ /** The file most recently snapshotted — i.e. last touched by the agent. */
29
+ lastTouched = null;
28
30
  // File-watcher checkpointing. Scoped to files kritya has itself snapshotted
29
31
  // this session — never a whole-repo recursive watch — so this can't pick up
30
32
  // noise from build output, node_modules, or unrelated files, and can't leak
@@ -43,6 +45,7 @@ export class UndoStack {
43
45
  }
44
46
  /** Capture the current state of a file before it is modified. */
45
47
  snapshot(absPath, relPath) {
48
+ this.lastTouched = { absPath, relPath };
46
49
  this.entries.push({ relPath, absPath, content: readOrNull(absPath), turn: this.turn });
47
50
  this.evictOldestTurnsOverCap();
48
51
  // A fresh change invalidates any redo history.
@@ -51,6 +54,14 @@ export class UndoStack {
51
54
  this.watchForExternalEdits(absPath, relPath);
52
55
  this.scheduleOwnWriteSync(absPath);
53
56
  }
57
+ /**
58
+ * The file the agent touched most recently this session, if any. Used by
59
+ * the Ctrl+E "open in $EDITOR" flow so there is always a sensible default
60
+ * target without the user naming a path.
61
+ */
62
+ lastTouchedFile() {
63
+ return this.lastTouched;
64
+ }
54
65
  /**
55
66
  * Re-read the file once the own-write grace window closes, and record that
56
67
  * as what we believe is on disk.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kritya",
3
- "version": "0.8.26-beta",
3
+ "version": "0.8.27-beta",
4
4
  "description": "Kritya — a lean, provider-agnostic terminal coding agent (NVIDIA, OpenAI, OpenRouter, Groq, Ollama, and more)",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -24,7 +24,7 @@
24
24
  "!dist/electron/**"
25
25
  ],
26
26
  "engines": {
27
- "node": ">=22"
27
+ "node": ">=22.19.0"
28
28
  },
29
29
  "scripts": {
30
30
  "build": "tsc",
@@ -37,6 +37,7 @@
37
37
  "format:check": "prettier --check .",
38
38
  "check:audit": "node scripts/check-audit.mjs",
39
39
  "check:install-scripts": "node scripts/check-install-scripts.mjs",
40
+ "check:typescript-setup": "node scripts/check-typescript-setup.mjs",
40
41
  "link": "npm run build && npm link",
41
42
  "prepublishOnly": "npm run build",
42
43
  "prepare": "husky",
@@ -57,9 +58,7 @@
57
58
  "dependencies": {
58
59
  "docx": "^9.7.1",
59
60
  "exceljs": "^4.4.0",
60
- "fast-glob": "^3.3.3",
61
- "ink": "^7.1.1",
62
- "ink-text-input": "^6.0.0",
61
+ "ink": "^8.0.0",
63
62
  "jszip": "^3.10.1",
64
63
  "mammoth": "^1.12.2",
65
64
  "openai": "^7.10.0",
@@ -68,7 +67,9 @@
68
67
  "pptxgenjs": "^4.0.1",
69
68
  "react": "^19.2.8",
70
69
  "string-width": "^8.2.2",
71
- "undici": "^7.29.0"
70
+ "tinyglobby": "^0.2.17",
71
+ "undici": "^8.11.2",
72
+ "wrap-ansi": "^10.0.2"
72
73
  },
73
74
  "devDependencies": {
74
75
  "@eslint/js": "^10.0.1",
@@ -82,14 +83,15 @@
82
83
  "husky": "^9.1.7",
83
84
  "ink-testing-library": "^4.0.0",
84
85
  "lint-staged": "^17.4.1",
85
- "prettier": "^3.3.0",
86
+ "prettier": "^3.9.0",
86
87
  "tsx": "^4.23.13",
87
- "typescript": "^6.0.3",
88
+ "typescript": "npm:@typescript/typescript6@^6.0.2",
89
+ "@typescript/native": "npm:typescript@^7.0.2",
88
90
  "typescript-eslint": "^8.69.0"
89
91
  },
90
92
  "overrides": {
91
- "brace-expansion": "^5.0.8",
92
- "fast-uri": "^3.1.7",
93
+ "brace-expansion": "^5.0.12",
94
+ "fast-uri": "^3.1.8",
93
95
  "exceljs": {
94
96
  "uuid": "^11.1.1",
95
97
  "unzipper": "^0.12.3",
@@ -118,10 +120,7 @@
118
120
  "publish": null,
119
121
  "files": [
120
122
  "dist/**/*",
121
- "electron/**/*",
122
- "package.json",
123
- "!src/**/*",
124
- "!scripts/**/*"
123
+ "electron/**/*"
125
124
  ],
126
125
  "win": {
127
126
  "target": "nsis"