@cairnvibe/indexer 0.2.3 → 0.2.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.
- package/dist/inject-widget.js +11 -6
- package/dist/manifest.js +36 -0
- package/dist/setup.js +19 -0
- package/package.json +1 -1
package/dist/inject-widget.js
CHANGED
|
@@ -36,12 +36,17 @@ const WRAPPER_COMPONENT_NAME = "CairnCopilot";
|
|
|
36
36
|
function wrapperSource(voice) {
|
|
37
37
|
// Real bug this closes: choosing voice during `cairn setup` used to save a
|
|
38
38
|
// DEEPGRAM_API_KEY that nothing ever read — the generated wrapper never
|
|
39
|
-
// passed speakEndpoint/transcribeEndpoint, so the widget had
|
|
40
|
-
// know voice existed regardless of whether a valid key was
|
|
41
|
-
// These routes only exist when
|
|
42
|
-
//
|
|
43
|
-
//
|
|
44
|
-
|
|
39
|
+
// passed speakEndpoint/transcribeEndpoint/realtimeUrl, so the widget had
|
|
40
|
+
// no way to know voice existed regardless of whether a valid key was
|
|
41
|
+
// configured. These routes only exist when setup.ts asked init.ts to
|
|
42
|
+
// scaffold them (voice: true) — never reference them here unwired to a
|
|
43
|
+
// real backend. realtimeUrl points at the port `cairn-realtime --with`
|
|
44
|
+
// (setup.ts rewrites the dev script to start it alongside next dev) —
|
|
45
|
+
// without that, a widget with realtimeUrl set just fails to connect,
|
|
46
|
+
// which reads as "voice doesn't work" with no clue why.
|
|
47
|
+
const voiceProps = voice
|
|
48
|
+
? '\n speakEndpoint="/api/copilot/speak"\n transcribeEndpoint="/api/copilot/transcribe"\n realtimeUrl="ws://localhost:3010"'
|
|
49
|
+
: "";
|
|
45
50
|
return `"use client";
|
|
46
51
|
|
|
47
52
|
import { Copilot } from "@cairnvibe/sdk";
|
package/dist/manifest.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.assembleManifest = assembleManifest;
|
|
4
|
+
exports.parseApiCall = parseApiCall;
|
|
4
5
|
const node_child_process_1 = require("node:child_process");
|
|
5
6
|
function assembleManifest(rootDir, facts, l2, l3) {
|
|
6
7
|
const globalElements = facts.frameworkElements.map((el) => toManifestElement(el, l3.globalElements.find((e) => e.id === el.id), "present in the root layout"));
|
|
@@ -27,6 +28,40 @@ function assembleManifest(rootDir, facts, l2, l3) {
|
|
|
27
28
|
conflicts: l2.conflicts,
|
|
28
29
|
};
|
|
29
30
|
}
|
|
31
|
+
const MUTATING_METHODS = new Set(["POST", "PUT", "PATCH", "DELETE"]);
|
|
32
|
+
/**
|
|
33
|
+
* Turns l1-scan's traced `"POST /api/items"`-shaped string into structured,
|
|
34
|
+
* executable data — this is what lets a `do` action actually run
|
|
35
|
+
* (verb-executor.ts) instead of only ever describing itself. Only real
|
|
36
|
+
* mutating methods count as an action; `"navigate ..."` (a Link) and a bare
|
|
37
|
+
* GET aren't "do" material — see ApiCallSchema's doc comment in
|
|
38
|
+
* @cairnvibe/core for the safety reasoning (bounded to calls a human
|
|
39
|
+
* developer already wrote and shipped, nothing invented at runtime).
|
|
40
|
+
*
|
|
41
|
+
* Only accepts a clean, static, same-origin relative path. l1-scan.ts's URL
|
|
42
|
+
* capture falls back to a call's raw source text when the first argument
|
|
43
|
+
* isn't a plain string literal — for a template literal (a per-row action
|
|
44
|
+
* built as `` `/api/items/${id}/archive` ``) that's literal backticks and a
|
|
45
|
+
* "${...}" hole, not a real fetchable URL; for a bare identifier or some
|
|
46
|
+
* other expression it isn't a URL at all. Rejecting both instead of
|
|
47
|
+
* guessing at resolving them is what keeps this bounded to calls that are
|
|
48
|
+
* actually safe to fire as-is — see ApiCallSchema's doc comment for the
|
|
49
|
+
* real gap this leaves (per-row actions aren't auto-executable yet).
|
|
50
|
+
*/
|
|
51
|
+
function parseApiCall(handlerCall) {
|
|
52
|
+
if (!handlerCall)
|
|
53
|
+
return null;
|
|
54
|
+
const spaceIndex = handlerCall.indexOf(" ");
|
|
55
|
+
if (spaceIndex === -1)
|
|
56
|
+
return null;
|
|
57
|
+
const method = handlerCall.slice(0, spaceIndex);
|
|
58
|
+
const url = handlerCall.slice(spaceIndex + 1);
|
|
59
|
+
if (!MUTATING_METHODS.has(method) || !url)
|
|
60
|
+
return null;
|
|
61
|
+
if (!/^\/[a-zA-Z0-9/_.-]*$/.test(url))
|
|
62
|
+
return null;
|
|
63
|
+
return { method: method, url };
|
|
64
|
+
}
|
|
30
65
|
function toManifestElement(el, elDesc, baseEvidence) {
|
|
31
66
|
const evidence = [baseEvidence];
|
|
32
67
|
if (el.handlerCall)
|
|
@@ -41,6 +76,7 @@ function toManifestElement(el, elDesc, baseEvidence) {
|
|
|
41
76
|
does: elDesc?.does ?? "Unknown — no description generated for this element.",
|
|
42
77
|
confidence: elDesc?.confidence ?? 0,
|
|
43
78
|
evidence,
|
|
79
|
+
apiCall: parseApiCall(el.handlerCall),
|
|
44
80
|
};
|
|
45
81
|
}
|
|
46
82
|
function elementFallbackSelector(el) {
|
package/dist/setup.js
CHANGED
|
@@ -295,5 +295,24 @@ async function runSetup(dir) {
|
|
|
295
295
|
console.log((0, ui_1.dim)("(--if-configured means a build with no key set yet skips this step instead of failing the whole build —"));
|
|
296
296
|
console.log((0, ui_1.dim)(" set the same key as an environment variable on whatever platform you deploy to.)"));
|
|
297
297
|
}
|
|
298
|
+
// 8. Wire the realtime voice relay into the normal dev workflow — the
|
|
299
|
+
// other real half of "voice was completely unwired." realtimeUrl on the
|
|
300
|
+
// widget (wired above) just fails to connect if nothing's actually
|
|
301
|
+
// listening on that port; found live, and indistinguishable from "voice
|
|
302
|
+
// doesn't work" with zero indication that a whole separate process needs
|
|
303
|
+
// to be running. `cairn-realtime --with "<original dev command>"` runs
|
|
304
|
+
// both from the one command a project's dev workflow already uses,
|
|
305
|
+
// instead of a second terminal nobody remembers to open. Wraps whatever
|
|
306
|
+
// `dev` already does (a custom server, Turbopack, anything) rather than
|
|
307
|
+
// replacing it — the realtime relay runs alongside it, not instead of it.
|
|
308
|
+
if (wantsVoice && pkg?.scripts?.dev && !pkg.scripts.dev.includes("cairn-realtime")) {
|
|
309
|
+
const pkgPath = node_path_1.default.join(absDir, "package.json");
|
|
310
|
+
const fresh = JSON.parse(node_fs_1.default.readFileSync(pkgPath, "utf8"));
|
|
311
|
+
const originalDev = fresh.scripts.dev;
|
|
312
|
+
fresh.scripts.dev = `cairn-realtime --port 3010 --with ${JSON.stringify(originalDev)}`;
|
|
313
|
+
node_fs_1.default.writeFileSync(pkgPath, JSON.stringify(fresh, null, 2) + "\n");
|
|
314
|
+
console.log((0, ui_1.green)('✓ wired the realtime voice relay into `npm run dev` — it now starts alongside your app automatically.'));
|
|
315
|
+
console.log((0, ui_1.dim)("(a missing/invalid Deepgram key skips voice only, never blocks your app's own dev server from starting.)"));
|
|
316
|
+
}
|
|
298
317
|
console.log(`\n${(0, ui_1.bold)("Done.")} \`npm run dev\` and ask it something.`);
|
|
299
318
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cairnvibe/indexer",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.5",
|
|
4
4
|
"description": "Cairn's analyzer and installer (the `cairn` CLI) — scans Next.js source or crawls any running app, and scaffolds the backend either way.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"publishConfig": { "access": "public" },
|