inflight-cli 2.1.7 → 2.2.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.
@@ -5,7 +5,7 @@ import { readGlobalAuth, readWorkspaceConfig, writeWorkspaceConfig } from "../li
5
5
  import { apiGetMe, apiDetectWidgetLocation } from "../lib/api.js";
6
6
  import { loginCommand } from "./login.js";
7
7
  import { shareCommand } from "./share.js";
8
- import { gatherProjectContext, hasInflightWidget, insertWidgetScript } from "../lib/framework.js";
8
+ import { gatherProjectContext, insertWidgetScript } from "../lib/framework.js";
9
9
  import { isGitRepo } from "../lib/git.js";
10
10
  import { installSkill } from "../lib/skill.js";
11
11
  function execSyncErrorDetail(err) {
@@ -83,7 +83,10 @@ export async function setupCommand() {
83
83
  process.exit(1);
84
84
  }
85
85
  // ── Step 4: Add widget script tag ──
86
- if (hasInflightWidget(cwd)) {
86
+ const hasWidget = (fileContents) => Object.values(fileContents).some((c) => c.includes("inflight.co/widget.js"));
87
+ const context = gatherProjectContext(cwd);
88
+ const alreadyHasWidget = hasWidget(context.fileContents);
89
+ if (alreadyHasWidget) {
87
90
  // Already present — move on silently
88
91
  }
89
92
  else {
@@ -91,14 +94,13 @@ export async function setupCommand() {
91
94
  spinner.start("Detecting framework...");
92
95
  let inserted = false;
93
96
  try {
94
- const context = gatherProjectContext(cwd);
95
97
  const location = await apiDetectWidgetLocation({
96
98
  apiKey: auth.apiKey,
97
99
  fileTree: context.fileTree,
98
100
  fileContents: context.fileContents,
99
101
  });
100
102
  if (location.file && location.insertAfter && location.confidence === "high") {
101
- const result = insertWidgetScript(cwd, location.file, location.insertAfter, widgetId);
103
+ const result = insertWidgetScript(context.root, location.file, location.insertAfter, widgetId);
102
104
  if (result) {
103
105
  spinner.stop(`Detected ${pc.bold(location.framework ?? "framework")} — widget script tag added to ${pc.cyan(location.file)}`);
104
106
  inserted = true;
@@ -126,7 +128,9 @@ export async function setupCommand() {
126
128
  p.cancel("Cancelled.");
127
129
  process.exit(0);
128
130
  }
129
- if (!hasInflightWidget(cwd)) {
131
+ // Re-scan to check if user added the widget manually
132
+ const rescan = gatherProjectContext(cwd);
133
+ if (!hasWidget(rescan.fileContents)) {
130
134
  const skip = await p.confirm({
131
135
  message: "Widget script not detected. Continue anyway?",
132
136
  initialValue: false,
@@ -5,6 +5,7 @@
5
5
  export declare function gatherProjectContext(cwd: string): {
6
6
  fileTree: string[];
7
7
  fileContents: Record<string, string>;
8
+ root: string;
8
9
  };
9
10
  /**
10
11
  * Returns true if any candidate file in the project already has the Inflight widget script.
@@ -14,4 +15,4 @@ export declare function hasInflightWidget(cwd: string): boolean;
14
15
  * Inserts the script tag into a file at the specified location.
15
16
  * Returns the file path that was modified, or null if insertion failed.
16
17
  */
17
- export declare function insertWidgetScript(cwd: string, file: string, insertAfter: string, widgetId: string): string | null;
18
+ export declare function insertWidgetScript(root: string, file: string, insertAfter: string, widgetId: string): string | null;
@@ -1,5 +1,6 @@
1
1
  import { existsSync, readFileSync, writeFileSync, readdirSync, statSync } from "fs";
2
2
  import { join, relative } from "path";
3
+ import { getGitRoot } from "./git.js";
3
4
  /** File patterns that are likely layout/root files where a script tag belongs */
4
5
  const CANDIDATE_PATTERNS = [
5
6
  "package.json",
@@ -27,10 +28,12 @@ const CANDIDATE_PATTERNS = [
27
28
  export function gatherProjectContext(cwd) {
28
29
  const fileTree = [];
29
30
  const fileContents = {};
30
- const dirsToScan = [cwd];
31
+ // Use git root so we scan the full repo, not just wherever the user ran the CLI from
32
+ const root = getGitRoot(cwd) ?? cwd;
33
+ const dirsToScan = [root];
31
34
  // If monorepo, add common subdirectories
32
35
  for (const dir of ["apps", "packages", "projects", "services", "libs"]) {
33
- const baseDir = join(cwd, dir);
36
+ const baseDir = join(root, dir);
34
37
  if (!existsSync(baseDir))
35
38
  continue;
36
39
  try {
@@ -49,7 +52,7 @@ export function gatherProjectContext(cwd) {
49
52
  // Add shallow file listing (1 level deep + key subdirs)
50
53
  try {
51
54
  for (const entry of readdirSync(dir)) {
52
- fileTree.push(relative(cwd, join(dir, entry)));
55
+ fileTree.push(relative(root, join(dir, entry)));
53
56
  }
54
57
  // Also list key subdirectories
55
58
  for (const sub of ["app", "src", "src/app", "src/layouts", "pages", "src/pages"]) {
@@ -57,7 +60,7 @@ export function gatherProjectContext(cwd) {
57
60
  if (!existsSync(subDir))
58
61
  continue;
59
62
  for (const entry of readdirSync(subDir)) {
60
- fileTree.push(relative(cwd, join(subDir, entry)));
63
+ fileTree.push(relative(root, join(subDir, entry)));
61
64
  }
62
65
  }
63
66
  }
@@ -67,7 +70,7 @@ export function gatherProjectContext(cwd) {
67
70
  // Read candidate files
68
71
  for (const pattern of CANDIDATE_PATTERNS) {
69
72
  const filePath = join(dir, pattern);
70
- const relPath = relative(cwd, filePath);
73
+ const relPath = relative(root, filePath);
71
74
  if (existsSync(filePath) && !fileContents[relPath]) {
72
75
  try {
73
76
  const content = readFileSync(filePath, "utf-8");
@@ -85,7 +88,7 @@ export function gatherProjectContext(cwd) {
85
88
  try {
86
89
  for (const f of readdirSync(layoutsDir).filter((f) => f.endsWith(".astro"))) {
87
90
  const filePath = join(layoutsDir, f);
88
- const relPath = relative(cwd, filePath);
91
+ const relPath = relative(root, filePath);
89
92
  if (!fileContents[relPath]) {
90
93
  const content = readFileSync(filePath, "utf-8");
91
94
  fileContents[relPath] = content.length > 3000 ? content.slice(0, 3000) + "\n... (truncated)" : content;
@@ -97,7 +100,7 @@ export function gatherProjectContext(cwd) {
97
100
  }
98
101
  }
99
102
  }
100
- return { fileTree, fileContents };
103
+ return { fileTree, fileContents, root };
101
104
  }
102
105
  /**
103
106
  * Returns true if any candidate file in the project already has the Inflight widget script.
@@ -110,9 +113,9 @@ export function hasInflightWidget(cwd) {
110
113
  * Inserts the script tag into a file at the specified location.
111
114
  * Returns the file path that was modified, or null if insertion failed.
112
115
  */
113
- export function insertWidgetScript(cwd, file, insertAfter, widgetId) {
116
+ export function insertWidgetScript(root, file, insertAfter, widgetId) {
114
117
  try {
115
- const filePath = join(cwd, file);
118
+ const filePath = join(root, file);
116
119
  const content = readFileSync(filePath, "utf-8");
117
120
  if (content.includes("inflight.co/widget.js")) {
118
121
  return file; // Already present
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "inflight-cli",
3
- "version": "2.1.7",
3
+ "version": "2.2.0",
4
4
  "description": "Get feedback directly on your staging URL",
5
5
  "bin": {
6
6
  "inflight": "dist/index.js",