@gajae-code/coding-agent 0.9.2 → 0.9.4

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 (86) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/types/build-metadata.d.ts +7 -0
  3. package/dist/types/capability/mcp.d.ts +3 -1
  4. package/dist/types/commands/mcp.d.ts +1 -1
  5. package/dist/types/config/keybindings.d.ts +2 -2
  6. package/dist/types/modes/components/hook-selector.d.ts +1 -0
  7. package/dist/types/modes/components/status-line/types.d.ts +6 -0
  8. package/dist/types/modes/components/status-line.d.ts +1 -0
  9. package/dist/types/modes/components/welcome.d.ts +1 -0
  10. package/dist/types/modes/rpc/rpc-client.d.ts +7 -2
  11. package/dist/types/modes/utils/ui-helpers.d.ts +12 -0
  12. package/dist/types/notifications/telegram-daemon.d.ts +2 -0
  13. package/dist/types/runtime-mcp/config-writer.d.ts +4 -3
  14. package/dist/types/runtime-mcp/types.d.ts +5 -4
  15. package/dist/types/session/agent-session.d.ts +16 -0
  16. package/dist/types/session/session-manager.d.ts +1 -0
  17. package/dist/types/tools/skill.d.ts +9 -8
  18. package/dist/types/utils/linkedom.d.ts +4 -0
  19. package/dist/types/utils/pasted-image-path.d.ts +5 -3
  20. package/package.json +11 -7
  21. package/scripts/build-binary.ts +2 -40
  22. package/scripts/compile-args.ts +96 -0
  23. package/scripts/generate-docs-index.ts +1 -0
  24. package/src/build-metadata.ts +104 -0
  25. package/src/capability/mcp.ts +3 -1
  26. package/src/cli/mcp-cli.ts +108 -26
  27. package/src/cli.ts +21 -0
  28. package/src/commands/mcp.ts +8 -8
  29. package/src/commands/stats.ts +6 -2
  30. package/src/config/keybindings.ts +2 -2
  31. package/src/config/mcp-schema.json +21 -17
  32. package/src/coordinator-mcp/server.ts +7 -4
  33. package/src/discovery/builtin.ts +14 -0
  34. package/src/discovery/mcp-json.ts +14 -0
  35. package/src/eval/js/executor.ts +7 -1
  36. package/src/gjc-runtime/state-runtime.ts +105 -12
  37. package/src/gjc-runtime/workflow-manifest.generated.json +4 -28
  38. package/src/gjc-runtime/workflow-manifest.ts +1 -7
  39. package/src/internal-urls/docs-index.generated.ts +3 -2
  40. package/src/internal-urls/gjc-protocol.ts +14 -1
  41. package/src/modes/components/assistant-message.ts +1 -1
  42. package/src/modes/components/hook-selector.ts +4 -0
  43. package/src/modes/components/session-selector.ts +2 -2
  44. package/src/modes/components/status-line/presets.ts +5 -7
  45. package/src/modes/components/status-line/segments.ts +14 -0
  46. package/src/modes/components/status-line/types.ts +6 -0
  47. package/src/modes/components/status-line.ts +13 -6
  48. package/src/modes/components/tool-execution.ts +1 -1
  49. package/src/modes/components/welcome.ts +4 -1
  50. package/src/modes/controllers/command-controller.ts +1 -1
  51. package/src/modes/controllers/event-controller.ts +9 -9
  52. package/src/modes/controllers/input-controller.ts +8 -2
  53. package/src/modes/controllers/selector-controller.ts +7 -3
  54. package/src/modes/interactive-mode.ts +12 -4
  55. package/src/modes/rpc/rpc-client.ts +30 -6
  56. package/src/modes/utils/ui-helpers.ts +154 -32
  57. package/src/notifications/telegram-daemon.ts +28 -2
  58. package/src/prompts/tools/skill.md +2 -2
  59. package/src/runtime-mcp/config-writer.ts +4 -3
  60. package/src/runtime-mcp/config.ts +1 -0
  61. package/src/runtime-mcp/types.ts +5 -4
  62. package/src/session/agent-session.ts +117 -3
  63. package/src/session/session-manager.ts +68 -40
  64. package/src/slash-commands/builtin-registry.ts +9 -4
  65. package/src/tools/bash-interactive.ts +9 -4
  66. package/src/tools/browser/readable.ts +2 -2
  67. package/src/tools/fetch.ts +5 -5
  68. package/src/tools/skill.ts +14 -11
  69. package/src/utils/linkedom.ts +14 -0
  70. package/src/utils/pasted-image-path.ts +23 -9
  71. package/src/web/scrapers/arxiv.ts +2 -2
  72. package/src/web/scrapers/go-pkg.ts +2 -2
  73. package/src/web/scrapers/iacr.ts +2 -2
  74. package/src/web/scrapers/readthedocs.ts +2 -2
  75. package/src/web/scrapers/twitter.ts +3 -2
  76. package/src/web/scrapers/wikipedia.ts +2 -2
  77. package/src/export/html/template.css +0 -1060
  78. package/src/export/html/template.html +0 -47
  79. package/src/export/html/template.js +0 -2314
  80. package/vendor/insane-search/engine/tests/test_hardening.py +0 -57
  81. package/vendor/insane-search/engine/tests/test_smoke.py +0 -152
  82. package/vendor/insane-search/engine/tests/test_u1.py +0 -200
  83. package/vendor/insane-search/engine/tests/test_u4.py +0 -131
  84. package/vendor/insane-search/engine/tests/test_u5.py +0 -163
  85. package/vendor/insane-search/engine/tests/test_u7.py +0 -124
  86. package/vendor/insane-search/engine/tests/test_u8.py +0 -216
@@ -1,12 +1,12 @@
1
1
  /**
2
2
  * Resolve pasted editor text to an image file path.
3
3
  *
4
- * Terminals insert a shell-escaped filesystem path when a file is drag-dropped
5
- * onto them (e.g. macOS `Screenshot\ 2026-07-07\ at\ 11.06.38 PM.png`, where
6
- * the visible "space" before AM/PM is U+202F and stays unescaped). When the
7
- * entire paste is a single path to an existing image file, the interactive
8
- * editor attaches the image and inserts an `[image N]` placeholder instead of
9
- * leaving the raw path in the prompt.
4
+ * Some terminal/clipboard integrations paste a temporary filesystem path after a
5
+ * copied image is pasted into the editor (for example `/tmp/clipboard-...png`).
6
+ * Only those recognized clipboard temp files are auto-attached and replaced with
7
+ * an `[image N] source="/path"` reference so the model receives both the image
8
+ * payload and the raw temp file path. Ordinary image paths remain literal prompt
9
+ * text; users attach saved files explicitly with `@path/to/image.png`.
10
10
  */
11
11
  import * as fs from "node:fs";
12
12
  import * as os from "node:os";
@@ -14,6 +14,7 @@ import * as path from "node:path";
14
14
  import { fileURLToPath } from "node:url";
15
15
 
16
16
  const IMAGE_FILE_EXTENSION_PATTERN = /\.(?:png|jpe?g|gif|webp)$/i;
17
+ const CLIPBOARD_TEMP_BASENAME_PATTERN = /^clipboard-\d{4}-\d{2}-\d{2}-\d{6}-[A-Za-z0-9-]+\.(?:png|jpe?g|gif|webp)$/i;
17
18
 
18
19
  export interface DecodePastedPathOptions {
19
20
  /**
@@ -150,16 +151,25 @@ function hasSupportedImageMagic(filePath: string): boolean {
150
151
  }
151
152
  }
152
153
 
154
+ function isRecognizedClipboardTempPath(filePath: string): boolean {
155
+ const resolved = path.resolve(filePath);
156
+ const tempRoot = path.resolve(os.tmpdir());
157
+ if (resolved !== tempRoot && !resolved.startsWith(`${tempRoot}${path.sep}`)) return false;
158
+ return CLIPBOARD_TEMP_BASENAME_PATTERN.test(path.basename(resolved));
159
+ }
160
+
153
161
  /**
154
- * Returns the resolved path when the whole pasted text is a single path to an
155
- * existing image file (verified by extension AND content signature),
156
- * otherwise `undefined` (the paste is inserted as text).
162
+ * Returns the resolved path when the whole pasted text is a recognized clipboard
163
+ * temp path to an existing image file, otherwise `undefined` (the paste is
164
+ * inserted as text). Arbitrary saved image paths are not auto-attached here;
165
+ * users attach them explicitly with `@path/to/image.png`.
157
166
  */
158
167
  export function resolvePastedImagePath(text: string, options?: ResolvePastedImagePathOptions): string | undefined {
159
168
  const candidate = decodePastedPathCandidate(text, options);
160
169
  if (!candidate || !IMAGE_FILE_EXTENSION_PATTERN.test(candidate)) return undefined;
161
170
 
162
171
  const resolved = path.resolve(options?.cwd ?? process.cwd(), candidate);
172
+ if (!isRecognizedClipboardTempPath(resolved)) return undefined;
163
173
  try {
164
174
  if (!fs.statSync(resolved).isFile()) return undefined;
165
175
  } catch {
@@ -168,3 +178,7 @@ export function resolvePastedImagePath(text: string, options?: ResolvePastedImag
168
178
  if (!hasSupportedImageMagic(resolved)) return undefined;
169
179
  return resolved;
170
180
  }
181
+
182
+ export function formatPastedImageReference(placeholder: string, imagePath: string): string {
183
+ return `${placeholder} source=${JSON.stringify(imagePath)}`;
184
+ }
@@ -1,4 +1,4 @@
1
- import { parseHTML } from "linkedom";
1
+ import { parseHtmlLazy } from "../../utils/linkedom";
2
2
  import type { RenderResult, SpecialHandler } from "./types";
3
3
  import { buildResult, loadPage } from "./types";
4
4
  import { convertWithMarkit, fetchBinary } from "./utils";
@@ -31,7 +31,7 @@ export const handleArxiv: SpecialHandler = async (
31
31
  if (!result.ok) return null;
32
32
 
33
33
  // Parse the Atom feed response
34
- const doc = parseHTML(result.content).document;
34
+ const doc = (await parseHtmlLazy(result.content)).document;
35
35
  const entry = doc.querySelector("entry");
36
36
 
37
37
  if (!entry) return null;
@@ -1,5 +1,5 @@
1
1
  import { tryParseJson } from "@gajae-code/utils";
2
- import { parseHTML } from "linkedom";
2
+ import { parseHtmlLazy } from "../../utils/linkedom";
3
3
  import type { RenderResult, SpecialHandler } from "./types";
4
4
  import { buildResult, htmlToBasicMarkdown, loadPage } from "./types";
5
5
 
@@ -97,7 +97,7 @@ export const handleGoPkg: SpecialHandler = async (
97
97
  });
98
98
  }
99
99
 
100
- const doc = parseHTML(pageResult.content).document;
100
+ const doc = (await parseHtmlLazy(pageResult.content)).document;
101
101
 
102
102
  // Extract actual module path from breadcrumb or header
103
103
  const breadcrumb = doc.querySelector(".go-Breadcrumb");
@@ -1,4 +1,4 @@
1
- import { parseHTML } from "linkedom";
1
+ import { parseHtmlLazy } from "../../utils/linkedom";
2
2
  import type { RenderResult, SpecialHandler } from "./types";
3
3
  import { buildResult, loadPage } from "./types";
4
4
  import { convertWithMarkit, fetchBinary } from "./utils";
@@ -30,7 +30,7 @@ export const handleIacr: SpecialHandler = async (
30
30
 
31
31
  if (!result.ok) return null;
32
32
 
33
- const doc = parseHTML(result.content).document;
33
+ const doc = (await parseHtmlLazy(result.content)).document;
34
34
 
35
35
  // Extract metadata from the page
36
36
  const title =
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Read the Docs handler for web-fetch
3
3
  */
4
- import { parseHTML } from "linkedom";
4
+ import { parseHtmlLazy } from "../../utils/linkedom";
5
5
  import { buildResult, htmlToBasicMarkdown, loadPage, type RenderResult, type SpecialHandler } from "./types";
6
6
 
7
7
  export const handleReadTheDocs: SpecialHandler = async (
@@ -39,7 +39,7 @@ export const handleReadTheDocs: SpecialHandler = async (
39
39
  }
40
40
 
41
41
  // Parse HTML
42
- const root = parseHTML(result.content).document;
42
+ const root = (await parseHtmlLazy(result.content)).document;
43
43
 
44
44
  // Extract main content from common Read the Docs selectors
45
45
  let mainContent =
@@ -1,5 +1,6 @@
1
- import { type HTMLElement, parseHTML } from "linkedom";
1
+ import type { HTMLElement } from "linkedom";
2
2
  import { ToolAbortError } from "../../tools/tool-errors";
3
+ import { parseHtmlLazy } from "../../utils/linkedom";
3
4
  import type { RenderResult, SpecialHandler } from "./types";
4
5
  import { buildResult, loadPage } from "./types";
5
6
 
@@ -33,7 +34,7 @@ export const handleTwitter: SpecialHandler = async (
33
34
 
34
35
  if (result.ok && result.content.length > 500) {
35
36
  // Parse the Nitter HTML
36
- const doc = parseHTML(result.content).document;
37
+ const doc = (await parseHtmlLazy(result.content)).document;
37
38
 
38
39
  // Extract tweet content
39
40
  const tweetContent = doc.querySelector(".tweet-content")?.textContent?.trim();
@@ -1,4 +1,4 @@
1
- import { parseHTML } from "linkedom";
1
+ import { parseHtmlLazy } from "../../utils/linkedom";
2
2
  import type { RenderResult, SpecialHandler } from "./types";
3
3
  import { buildResult, loadPage } from "./types";
4
4
 
@@ -45,7 +45,7 @@ export const handleWikipedia: SpecialHandler = async (
45
45
  const contentResult = await loadPage(contentUrl, { timeout, signal });
46
46
 
47
47
  if (contentResult.ok) {
48
- const doc = parseHTML(contentResult.content).document;
48
+ const doc = (await parseHtmlLazy(contentResult.content)).document;
49
49
 
50
50
  // Extract main content sections
51
51
  const sections = doc.querySelectorAll("section");