netlify-cli 21.2.1 → 21.4.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 (36) hide show
  1. package/dist/commands/api/api.d.ts.map +1 -1
  2. package/dist/commands/api/api.js +1 -1
  3. package/dist/commands/api/api.js.map +1 -1
  4. package/dist/commands/base-command.d.ts.map +1 -1
  5. package/dist/commands/base-command.js +1 -1
  6. package/dist/commands/base-command.js.map +1 -1
  7. package/dist/commands/deploy/deploy.js +1 -1
  8. package/dist/commands/deploy/deploy.js.map +1 -1
  9. package/dist/commands/watch/watch.js.map +1 -1
  10. package/dist/lib/api.d.ts +1 -1
  11. package/dist/lib/api.d.ts.map +1 -1
  12. package/dist/recipes/ai-context/context.d.ts +28 -2
  13. package/dist/recipes/ai-context/context.d.ts.map +1 -1
  14. package/dist/recipes/ai-context/context.js +100 -6
  15. package/dist/recipes/ai-context/context.js.map +1 -1
  16. package/dist/recipes/ai-context/index.d.ts +1 -1
  17. package/dist/recipes/ai-context/index.d.ts.map +1 -1
  18. package/dist/recipes/ai-context/index.js +103 -55
  19. package/dist/recipes/ai-context/index.js.map +1 -1
  20. package/dist/tsconfig.build.tsbuildinfo +1 -1
  21. package/dist/utils/command-helpers.d.ts +1 -1
  22. package/dist/utils/command-helpers.d.ts.map +1 -1
  23. package/dist/utils/command-helpers.js.map +1 -1
  24. package/dist/utils/dev.d.ts +1 -1
  25. package/dist/utils/dev.d.ts.map +1 -1
  26. package/dist/utils/dev.js.map +1 -1
  27. package/dist/utils/env/index.d.ts +1 -1
  28. package/dist/utils/env/index.d.ts.map +1 -1
  29. package/dist/utils/get-site.d.ts +1 -1
  30. package/dist/utils/get-site.d.ts.map +1 -1
  31. package/dist/utils/init/config-github.js.map +1 -1
  32. package/dist/utils/init/utils.d.ts +1 -1
  33. package/dist/utils/init/utils.d.ts.map +1 -1
  34. package/dist/utils/init/utils.js.map +1 -1
  35. package/npm-shrinkwrap.json +77 -77
  36. package/package.json +5 -5
@@ -1,25 +1,40 @@
1
1
  import { resolve } from 'node:path';
2
2
  import inquirer from 'inquirer';
3
- import semver from 'semver';
4
- import { chalk, logAndThrowError, log, version } from '../../utils/command-helpers.js';
5
- import { applyOverrides, downloadFile, getExistingContext, parseContextFile, writeFile, FILE_NAME, NETLIFY_PROVIDER, } from './context.js';
3
+ import execa from 'execa';
4
+ import { logAndThrowError, log, version } from '../../utils/command-helpers.js';
5
+ import { getExistingContext, NTL_DEV_MCP_FILE_NAME, getContextConsumers, deleteFile, downloadAndWriteContextFiles, } from './context.js';
6
6
  export const description = 'Manage context files for AI tools';
7
- const presets = [
8
- { name: 'Windsurf rules (.windsurf/rules/)', value: '.windsurf/rules' },
9
- { name: 'Cursor rules (.cursor/rules/)', value: '.cursor/rules' },
10
- { name: 'Custom location', value: '' },
11
- ];
12
- const promptForPath = async () => {
13
- const { presetPath } = await inquirer.prompt([
7
+ // context consumers endpoints returns all supported IDE and other consumers
8
+ // that can be used to pull context files. It also includes a catchall consumer
9
+ // for outlining all context that an unspecified consumer would handle.
10
+ const allContextConsumers = (await getContextConsumers(version)).filter((consumer) => !consumer.hideFromCLI);
11
+ const cliContextConsumers = allContextConsumers.filter((consumer) => !consumer.hideFromCLI);
12
+ const rulesForDefaultConsumer = allContextConsumers.find((consumer) => consumer.key === 'catchall-consumer') ?? {
13
+ key: 'catchall-consumer',
14
+ path: './ai-context',
15
+ presentedName: '',
16
+ ext: 'mdc',
17
+ contextScopes: {},
18
+ hideFromCLI: true,
19
+ };
20
+ const presets = cliContextConsumers.map((consumer) => ({
21
+ name: consumer.presentedName,
22
+ value: consumer.key,
23
+ }));
24
+ // always add the custom location option (not preset from API)
25
+ presets.push({ name: 'Custom location', value: rulesForDefaultConsumer.key });
26
+ const promptForContextConsumerSelection = async () => {
27
+ const { consumerKey } = await inquirer.prompt([
14
28
  {
15
- name: 'presetPath',
29
+ name: 'consumerKey',
16
30
  message: 'Where should we put the context files?',
17
31
  type: 'list',
18
32
  choices: presets,
19
33
  },
20
34
  ]);
21
- if (presetPath) {
22
- return presetPath;
35
+ const contextConsumer = consumerKey ? cliContextConsumers.find((consumer) => consumer.key === consumerKey) : null;
36
+ if (contextConsumer) {
37
+ return contextConsumer;
23
38
  }
24
39
  const { customPath } = await inquirer.prompt([
25
40
  {
@@ -30,55 +45,88 @@ const promptForPath = async () => {
30
45
  },
31
46
  ]);
32
47
  if (customPath) {
33
- return customPath;
48
+ return { ...rulesForDefaultConsumer, path: customPath || rulesForDefaultConsumer.path };
34
49
  }
35
50
  log('You must select a path.');
36
- return promptForPath();
51
+ return promptForContextConsumerSelection();
52
+ };
53
+ /**
54
+ * Checks if a command belongs to a known IDEs by checking if it includes a specific string.
55
+ * For example, the command that starts windsurf looks something like "/applications/windsurf.app/contents/...".
56
+ */
57
+ const getConsumerKeyFromCommand = (command) => {
58
+ // The actual command is something like "/applications/windsurf.app/contents/...", but we are only looking for windsurf
59
+ const match = cliContextConsumers.find((consumer) => consumer.consumerProcessCmd && command.includes(consumer.consumerProcessCmd));
60
+ return match ? match.key : null;
61
+ };
62
+ /**
63
+ * Receives a process ID (pid) and returns both the command that the process was run with and its parent process ID. If the process is a known IDE, also returns information about that IDE.
64
+ */
65
+ const getCommandAndParentPID = async (pid) => {
66
+ const { stdout } = await execa('ps', ['-p', String(pid), '-o', 'ppid=,comm=']);
67
+ const output = stdout.trim();
68
+ const spaceIndex = output.indexOf(' ');
69
+ const parentPID = output.substring(0, spaceIndex);
70
+ const command = output.substring(spaceIndex + 1).toLowerCase();
71
+ return {
72
+ parentPID: Number(parentPID),
73
+ command,
74
+ consumerKey: getConsumerKeyFromCommand(command),
75
+ };
37
76
  };
38
- export const run = async ({ args, command }) => {
39
- // Start the download in the background while we wait for the prompts.
40
- const download = downloadFile(version).catch(() => null);
41
- const filePath = args[0] || (await promptForPath());
42
- const { contents: downloadedFile, minimumCLIVersion } = (await download) ?? {};
43
- if (!downloadedFile) {
44
- return logAndThrowError('An error occurred when pulling the latest context files. Please try again.');
77
+ const getPathByDetectingIDE = async () => {
78
+ // Go up the chain of ancestor process IDs and find if one of their commands matches an IDE.
79
+ const ppid = process.ppid;
80
+ let result;
81
+ try {
82
+ result = await getCommandAndParentPID(ppid);
83
+ while (result.parentPID !== 1 && !result.consumerKey) {
84
+ result = await getCommandAndParentPID(result.parentPID);
85
+ }
45
86
  }
46
- if (minimumCLIVersion && semver.lt(version, minimumCLIVersion)) {
47
- return logAndThrowError(`This command requires version ${minimumCLIVersion} or above of the Netlify CLI. Refer to ${chalk.underline('https://ntl.fyi/update-cli')} for information on how to update.`);
87
+ catch {
88
+ // The command "ps -p {pid} -o ppid=,comm=" didn't work,
89
+ // perhaps we are on a machine that doesn't support it.
90
+ return null;
48
91
  }
49
- const absoluteFilePath = resolve(command?.workingDir ?? '', filePath, FILE_NAME);
50
- const existing = await getExistingContext(absoluteFilePath);
51
- const remote = parseContextFile(downloadedFile);
52
- let { contents } = remote;
53
- // Does a file already exist at this path?
54
- if (existing) {
55
- // If it's a file we've created, let's check the version and bail if we're
56
- // already on the latest, otherwise rewrite it with the latest version.
57
- if (existing.provider?.toLowerCase() === NETLIFY_PROVIDER) {
58
- if (remote?.version === existing.version) {
59
- log(`You're all up to date! ${chalk.underline(absoluteFilePath)} contains the latest version of the context files.`);
60
- return;
61
- }
62
- // We must preserve any overrides found in the existing file.
63
- contents = applyOverrides(remote.contents, existing.overrides?.innerContents);
92
+ if (result?.consumerKey) {
93
+ const contextConsumer = cliContextConsumers.find((consumer) => consumer.key === result.consumerKey);
94
+ if (contextConsumer) {
95
+ return contextConsumer;
64
96
  }
65
- else {
66
- // If this is not a file we've created, we can offer to overwrite it and
67
- // preserve the existing contents by moving it to the overrides slot.
68
- const { confirm } = await inquirer.prompt({
69
- type: 'confirm',
70
- name: 'confirm',
71
- message: `A context file already exists at ${chalk.underline(absoluteFilePath)}. It has not been created by the Netlify CLI, but we can update it while preserving its existing content. Can we proceed?`,
72
- default: true,
73
- });
74
- if (!confirm) {
75
- return;
76
- }
77
- // Whatever exists in the file goes in the overrides block.
78
- contents = applyOverrides(remote.contents, existing.contents);
97
+ }
98
+ return null;
99
+ };
100
+ export const run = async (runOptions) => {
101
+ const { args, command } = runOptions;
102
+ let consumer = null;
103
+ const filePath = args[0];
104
+ if (filePath) {
105
+ consumer = { ...rulesForDefaultConsumer, path: filePath };
106
+ }
107
+ if (!consumer && process.env.AI_CONTEXT_SKIP_DETECTION !== 'true') {
108
+ consumer = await getPathByDetectingIDE();
109
+ }
110
+ if (!consumer) {
111
+ consumer = await promptForContextConsumerSelection();
112
+ }
113
+ if (!consumer?.contextScopes) {
114
+ log('No context files found for this consumer. Try again or let us know if this happens again via our support channels.');
115
+ return;
116
+ }
117
+ try {
118
+ await downloadAndWriteContextFiles(consumer, runOptions);
119
+ // the deprecated MCP file path
120
+ // let's remove that file if it exists.
121
+ const priorContextFilePath = resolve(command?.workingDir ?? '', consumer.path, NTL_DEV_MCP_FILE_NAME);
122
+ const priorExists = await getExistingContext(priorContextFilePath);
123
+ if (priorExists) {
124
+ await deleteFile(priorContextFilePath);
79
125
  }
126
+ log('All context files have been added!');
127
+ }
128
+ catch (error) {
129
+ logAndThrowError(error);
80
130
  }
81
- await writeFile(absoluteFilePath, contents);
82
- log(`${existing ? 'Updated' : 'Created'} context files at ${chalk.underline(absoluteFilePath)}`);
83
131
  };
84
132
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/recipes/ai-context/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/recipes/ai-context/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAEnC,OAAO,QAAQ,MAAM,UAAU,CAAA;AAC/B,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,OAAO,EAAE,gBAAgB,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,gCAAgC,CAAA;AAE/E,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,mBAAmB,EAEnB,UAAU,EACV,4BAA4B,GAC7B,MAAM,cAAc,CAAA;AAErB,MAAM,CAAC,MAAM,WAAW,GAAG,mCAAmC,CAAA;AAE9D,4EAA4E;AAC5E,+EAA+E;AAC/E,uEAAuE;AACvE,MAAM,mBAAmB,GAAG,CAAC,MAAM,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;AAC5G,MAAM,mBAAmB,GAAG,mBAAmB,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAA;AAE3F,MAAM,uBAAuB,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,KAAK,mBAAmB,CAAC,IAAI;IAC9G,GAAG,EAAE,mBAAmB;IACxB,IAAI,EAAE,cAAc;IACpB,aAAa,EAAE,EAAE;IACjB,GAAG,EAAE,KAAK;IACV,aAAa,EAAE,EAAE;IACjB,WAAW,EAAE,IAAI;CAClB,CAAA;AAED,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAG,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;IACrD,IAAI,EAAE,QAAQ,CAAC,aAAa;IAC5B,KAAK,EAAE,QAAQ,CAAC,GAAG;CACpB,CAAC,CAAC,CAAA;AAEH,8DAA8D;AAC9D,OAAO,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,iBAAiB,EAAE,KAAK,EAAE,uBAAuB,CAAC,GAAG,EAAE,CAAC,CAAA;AAE7E,MAAM,iCAAiC,GAAG,KAAK,IAA6B,EAAE;IAC5E,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;QAC5C;YACE,IAAI,EAAE,aAAa;YACnB,OAAO,EAAE,wCAAwC;YACjD,IAAI,EAAE,MAAM;YACZ,OAAO,EAAE,OAAO;SACjB;KACF,CAAC,CAAA;IAEF,MAAM,eAAe,GAAG,WAAW,CAAC,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,KAAK,WAAW,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IACjH,IAAI,eAAe,EAAE,CAAC;QACpB,OAAO,eAAe,CAAA;IACxB,CAAC;IAED,MAAM,EAAE,UAAU,EAAE,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;QAC3C;YACE,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,YAAY;YAClB,OAAO,EAAE,wFAAwF;YACjG,OAAO,EAAE,cAAc;SACxB;KACF,CAAC,CAAA;IAEF,IAAI,UAAU,EAAE,CAAC;QACf,OAAO,EAAE,GAAG,uBAAuB,EAAE,IAAI,EAAE,UAAU,IAAI,uBAAuB,CAAC,IAAI,EAAE,CAAA;IACzF,CAAC;IAED,GAAG,CAAC,yBAAyB,CAAC,CAAA;IAE9B,OAAO,iCAAiC,EAAE,CAAA;AAC5C,CAAC,CAAA;AAED;;;GAGG;AACH,MAAM,yBAAyB,GAAG,CAAC,OAAe,EAAiB,EAAE;IACnE,uHAAuH;IACvH,MAAM,KAAK,GAAG,mBAAmB,CAAC,IAAI,CACpC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,kBAAkB,IAAI,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,kBAAkB,CAAC,CAC3F,CAAA;IACD,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAA;AACjC,CAAC,CAAA;AAED;;GAEG;AACH,MAAM,sBAAsB,GAAG,KAAK,EAClC,GAAW,EAKV,EAAE;IACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC,CAAA;IAC9E,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,CAAA;IAC5B,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;IACtC,MAAM,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC,EAAE,UAAU,CAAC,CAAA;IACjD,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,WAAW,EAAE,CAAA;IAC9D,OAAO;QACL,SAAS,EAAE,MAAM,CAAC,SAAS,CAAC;QAC5B,OAAO;QACP,WAAW,EAAE,yBAAyB,CAAC,OAAO,CAAC;KAChD,CAAA;AACH,CAAC,CAAA;AAED,MAAM,qBAAqB,GAAG,KAAK,IAAoC,EAAE;IACvE,4FAA4F;IAC5F,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAA;IACzB,IAAI,MAA0D,CAAA;IAC9D,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,sBAAsB,CAAC,IAAI,CAAC,CAAA;QAC3C,OAAO,MAAM,CAAC,SAAS,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC;YACrD,MAAM,GAAG,MAAM,sBAAsB,CAAC,MAAM,CAAC,SAAS,CAAC,CAAA;QACzD,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,wDAAwD;QACxD,uDAAuD;QACvD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,IAAI,MAAM,EAAE,WAAW,EAAE,CAAC;QACxB,MAAM,eAAe,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,GAAG,KAAK,MAAM,CAAC,WAAW,CAAC,CAAA;QACnG,IAAI,eAAe,EAAE,CAAC;YACpB,OAAO,eAAe,CAAA;QACxB,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAA;AACb,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,GAAG,GAAG,KAAK,EAAE,UAA4B,EAAE,EAAE;IACxD,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,GAAG,UAAU,CAAA;IACpC,IAAI,QAAQ,GAA0B,IAAI,CAAA;IAC1C,MAAM,QAAQ,GAAkB,IAAI,CAAC,CAAC,CAAC,CAAA;IAEvC,IAAI,QAAQ,EAAE,CAAC;QACb,QAAQ,GAAG,EAAE,GAAG,uBAAuB,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAA;IAC3D,CAAC;IAED,IAAI,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,yBAAyB,KAAK,MAAM,EAAE,CAAC;QAClE,QAAQ,GAAG,MAAM,qBAAqB,EAAE,CAAA;IAC1C,CAAC;IAED,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,QAAQ,GAAG,MAAM,iCAAiC,EAAE,CAAA;IACtD,CAAC;IAED,IAAI,CAAC,QAAQ,EAAE,aAAa,EAAE,CAAC;QAC7B,GAAG,CACD,oHAAoH,CACrH,CAAA;QACD,OAAM;IACR,CAAC;IAED,IAAI,CAAC;QACH,MAAM,4BAA4B,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAA;QAExD,+BAA+B;QAC/B,uCAAuC;QACvC,MAAM,oBAAoB,GAAG,OAAO,CAAC,OAAO,EAAE,UAAU,IAAI,EAAE,EAAE,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC,CAAA;QACrG,MAAM,WAAW,GAAG,MAAM,kBAAkB,CAAC,oBAAoB,CAAC,CAAA;QAClE,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,UAAU,CAAC,oBAAoB,CAAC,CAAA;QACxC,CAAC;QAED,GAAG,CAAC,oCAAoC,CAAC,CAAA;IAC3C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,gBAAgB,CAAC,KAAK,CAAC,CAAA;IACzB,CAAC;AACH,CAAC,CAAA"}