thymian 0.0.1 → 0.1.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 (51) hide show
  1. package/README.md +19 -1
  2. package/bin/run.js +26 -0
  3. package/dist/commands/analyze.d.ts +9 -0
  4. package/dist/commands/analyze.d.ts.map +1 -0
  5. package/dist/commands/analyze.js +28 -0
  6. package/dist/commands/analyze.js.map +1 -0
  7. package/dist/commands/config/show.d.ts +9 -0
  8. package/dist/commands/config/show.d.ts.map +1 -0
  9. package/dist/commands/config/show.js +35 -0
  10. package/dist/commands/config/show.js.map +1 -0
  11. package/dist/commands/feedback.d.ts +9 -0
  12. package/dist/commands/feedback.d.ts.map +1 -0
  13. package/dist/commands/feedback.js +95 -0
  14. package/dist/commands/feedback.js.map +1 -0
  15. package/dist/commands/generate/config.d.ts +15 -0
  16. package/dist/commands/generate/config.d.ts.map +1 -0
  17. package/dist/commands/generate/config.js +176 -0
  18. package/dist/commands/generate/config.js.map +1 -0
  19. package/dist/commands/lint.d.ts +7 -0
  20. package/dist/commands/lint.d.ts.map +1 -0
  21. package/dist/commands/lint.js +24 -0
  22. package/dist/commands/lint.js.map +1 -0
  23. package/dist/commands/plugins/list.d.ts +6 -0
  24. package/dist/commands/plugins/list.d.ts.map +1 -0
  25. package/dist/commands/plugins/list.js +14 -0
  26. package/dist/commands/plugins/list.js.map +1 -0
  27. package/dist/commands/schema.d.ts +5 -0
  28. package/dist/commands/schema.d.ts.map +1 -0
  29. package/dist/commands/schema.js +30 -0
  30. package/dist/commands/schema.js.map +1 -0
  31. package/dist/commands/serve.d.ts +8 -0
  32. package/dist/commands/serve.d.ts.map +1 -0
  33. package/dist/commands/serve.js +31 -0
  34. package/dist/commands/serve.js.map +1 -0
  35. package/dist/commands/test.d.ts +10 -0
  36. package/dist/commands/test.d.ts.map +1 -0
  37. package/dist/commands/test.js +33 -0
  38. package/dist/commands/test.js.map +1 -0
  39. package/dist/create-email-issue-for-error.d.ts +3 -0
  40. package/dist/create-email-issue-for-error.d.ts.map +1 -0
  41. package/dist/create-email-issue-for-error.js +31 -0
  42. package/dist/create-email-issue-for-error.js.map +1 -0
  43. package/dist/create-github-issue-url-for-error.d.ts +3 -0
  44. package/dist/create-github-issue-url-for-error.d.ts.map +1 -0
  45. package/dist/create-github-issue-url-for-error.js +45 -0
  46. package/dist/create-github-issue-url-for-error.js.map +1 -0
  47. package/dist/hooks/feedback.d.ts +4 -0
  48. package/dist/hooks/feedback.d.ts.map +1 -0
  49. package/dist/hooks/feedback.js +8 -0
  50. package/dist/hooks/feedback.js.map +1 -0
  51. package/package.json +62 -8
package/README.md CHANGED
@@ -1 +1,19 @@
1
- reserved
1
+ # @thymian/cli
2
+
3
+ Main CLI entry point for Thymian - a lightweight, language-agnostic library that helps you build robust APIs by adding resilience testing and HTTP conformance validation to your development workflow.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @thymian/cli
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```bash
14
+ npx thymian run
15
+ ```
16
+
17
+ ## Documentation
18
+
19
+ For comprehensive documentation, guides, and API reference, visit [Thymian Documentation](https://thymian.dev/).
package/bin/run.js ADDED
@@ -0,0 +1,26 @@
1
+ #!/usr/bin/env node
2
+
3
+ import path from 'node:path';
4
+
5
+ import { getPluginNames, oclif } from '@thymian/common-cli';
6
+
7
+ const dirname = import.meta.dirname;
8
+
9
+ const thymianPath = import.meta.url.includes('node_modules')
10
+ ? path.join(dirname, '..')
11
+ : path.join(dirname, 'node_modules', '@thymian', 'cli');
12
+
13
+ const pluginsPath = import.meta.url.includes('node_modules')
14
+ ? thymianPath
15
+ : path.join(dirname, '..');
16
+
17
+ await oclif.execute({
18
+ dir: thymianPath,
19
+ loadOptions: {
20
+ pluginAdditions: {
21
+ core: await getPluginNames(),
22
+ path: pluginsPath,
23
+ },
24
+ root: thymianPath,
25
+ },
26
+ });
@@ -0,0 +1,9 @@
1
+ import { BaseCliRunCommand } from '@thymian/common-cli';
2
+ export default class Analyze extends BaseCliRunCommand<typeof Analyze> {
3
+ static description: string;
4
+ static examples: string[];
5
+ static requiresSpecifications: boolean;
6
+ static requiresTraffic: boolean;
7
+ run(): Promise<void>;
8
+ }
9
+ //# sourceMappingURL=analyze.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.d.ts","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EAKlB,MAAM,qBAAqB,CAAC;AAM7B,MAAM,CAAC,OAAO,OAAO,OAAQ,SAAQ,iBAAiB,CAAC,OAAO,OAAO,CAAC;IACpE,OAAgB,WAAW,SACuD;IAElF,OAAgB,QAAQ,WAItB;IAEF,OAAgB,sBAAsB,UAAS;IAC/C,OAAgB,eAAe,UAAQ;IAExB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA0BpC"}
@@ -0,0 +1,28 @@
1
+ import { BaseCliRunCommand, createSeverityRuleFilter, handleWorkflowOutcome, mergeRuleSets, resolveRuleSeverity, } from '@thymian/common-cli';
2
+ export default class Analyze extends BaseCliRunCommand {
3
+ static description = 'Analyze recorded API traffic against specifications and configured rule sets.';
4
+ static examples = [
5
+ '<%= config.bin %> <%= command.id %>',
6
+ '<%= config.bin %> <%= command.id %> --traffic har:./traffic.har',
7
+ '<%= config.bin %> <%= command.id %> --spec openapi:./openapi.yaml --traffic har:./traffic.har',
8
+ ];
9
+ static requiresSpecifications = false;
10
+ static requiresTraffic = true;
11
+ async run() {
12
+ const specifications = this.thymianConfig.specifications ?? [];
13
+ const traffic = this.thymianConfig.traffic ?? [];
14
+ const ruleSets = mergeRuleSets(this.thymianConfig.ruleSets, this.flags['rule-set']);
15
+ const ruleSeverity = resolveRuleSeverity(this.thymianConfig.ruleSeverity, this.flags['rule-severity']);
16
+ const outcome = await this.thymian.run(async () => {
17
+ return await this.thymian.analyze({
18
+ specification: specifications.length > 0 ? specifications : undefined,
19
+ traffic,
20
+ rules: ruleSets,
21
+ rulesConfig: this.thymianConfig.rules,
22
+ ruleFilter: createSeverityRuleFilter(ruleSeverity),
23
+ });
24
+ });
25
+ handleWorkflowOutcome(this, outcome);
26
+ }
27
+ }
28
+ //# sourceMappingURL=analyze.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyze.js","sourceRoot":"","sources":["../../src/commands/analyze.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EACrB,aAAa,EACb,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAM7B,MAAM,CAAC,OAAO,OAAO,OAAQ,SAAQ,iBAAiC;IACpE,MAAM,CAAU,WAAW,GACzB,+EAA+E,CAAC;IAElF,MAAM,CAAU,QAAQ,GAAG;QACzB,qCAAqC;QACrC,iEAAiE;QACjE,+FAA+F;KAChG,CAAC;IAEF,MAAM,CAAU,sBAAsB,GAAG,KAAK,CAAC;IAC/C,MAAM,CAAU,eAAe,GAAG,IAAI,CAAC;IAE9B,KAAK,CAAC,GAAG;QAChB,MAAM,cAAc,GAAG,IAAI,CAAC,aAAa,CAAC,cAAc,IAAI,EAAE,CAAC;QAC/D,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC,OAAO,IAAI,EAAE,CAAC;QAEjD,MAAM,QAAQ,GAAG,aAAa,CAC5B,IAAI,CAAC,aAAa,CAAC,QAAQ,EAC3B,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CACvB,CAAC;QAEF,MAAM,YAAY,GAAG,mBAAmB,CACtC,IAAI,CAAC,aAAa,CAAC,YAAY,EAC/B,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAC5B,CAAC;QAEF,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE;YAChD,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;gBAChC,aAAa,EAAE,cAAc,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,cAAc,CAAC,CAAC,CAAC,SAAS;gBACrE,OAAO;gBACP,KAAK,EAAE,QAAQ;gBACf,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,KAAK;gBACrC,UAAU,EAAE,wBAAwB,CAAC,YAAY,CAAC;aACnD,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,qBAAqB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { BaseCliRunCommand } from '@thymian/common-cli';
2
+ export default class ShowConfig extends BaseCliRunCommand<typeof ShowConfig> {
3
+ static description: string;
4
+ static flags: {
5
+ yaml: import("@oclif/core/interfaces").BooleanFlag<boolean>;
6
+ };
7
+ run(): Promise<void>;
8
+ }
9
+ //# sourceMappingURL=show.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"show.d.ts","sourceRoot":"","sources":["../../../src/commands/config/show.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAIxD,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,iBAAiB,CAAC,OAAO,UAAU,CAAC;IAC1E,OAAgB,WAAW,SAA6C;IAExE,OAAgB,KAAK;;MAMnB;IACW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAsBlC"}
@@ -0,0 +1,35 @@
1
+ import { BaseCliRunCommand } from '@thymian/common-cli';
2
+ import { Flags, ux } from '@thymian/common-cli/oclif';
3
+ import { stringify } from '@thymian/common-cli/yaml';
4
+ export default class ShowConfig extends BaseCliRunCommand {
5
+ static description = 'Show the current Thymian configuration.';
6
+ static flags = {
7
+ yaml: Flags.boolean({
8
+ default: false,
9
+ allowNo: true,
10
+ description: 'Output configuration in YAML format.',
11
+ }),
12
+ };
13
+ async run() {
14
+ if (this.flags.yaml) {
15
+ this.log(stringify(this.thymianConfig));
16
+ }
17
+ else {
18
+ this.log(ux.colorizeJson(this.thymianConfig, {
19
+ pretty: true,
20
+ theme: {
21
+ brace: '#00FFFF',
22
+ bracket: 'rgb(0, 255, 255)',
23
+ colon: 'dim',
24
+ comma: 'yellow',
25
+ key: 'bold',
26
+ string: 'green',
27
+ number: 'blue',
28
+ boolean: 'cyan',
29
+ null: 'redBright',
30
+ },
31
+ }));
32
+ }
33
+ }
34
+ }
35
+ //# sourceMappingURL=show.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"show.js","sourceRoot":"","sources":["../../../src/commands/config/show.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,MAAM,2BAA2B,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,0BAA0B,CAAC;AAErD,MAAM,CAAC,OAAO,OAAO,UAAW,SAAQ,iBAAoC;IAC1E,MAAM,CAAU,WAAW,GAAG,yCAAyC,CAAC;IAExE,MAAM,CAAU,KAAK,GAAG;QACtB,IAAI,EAAE,KAAK,CAAC,OAAO,CAAC;YAClB,OAAO,EAAE,KAAK;YACd,OAAO,EAAE,IAAI;YACb,WAAW,EAAE,sCAAsC;SACpD,CAAC;KACH,CAAC;IACK,KAAK,CAAC,GAAG;QACd,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;YACpB,IAAI,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC;QAC1C,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,GAAG,CACN,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,aAAa,EAAE;gBAClC,MAAM,EAAE,IAAI;gBACZ,KAAK,EAAE;oBACL,KAAK,EAAE,SAAS;oBAChB,OAAO,EAAE,kBAAkB;oBAC3B,KAAK,EAAE,KAAK;oBACZ,KAAK,EAAE,QAAQ;oBACf,GAAG,EAAE,MAAM;oBACX,MAAM,EAAE,OAAO;oBACf,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,MAAM;oBACf,IAAI,EAAE,WAAW;iBAClB;aACF,CAAC,CACH,CAAC;QACJ,CAAC;IACH,CAAC"}
@@ -0,0 +1,9 @@
1
+ import { ThymianBaseCommand } from '@thymian/common-cli';
2
+ export declare class Feedback extends ThymianBaseCommand<typeof Feedback> {
3
+ protected static CONTACT: string;
4
+ shouldSuppressFeedback(): boolean;
5
+ run(): Promise<void>;
6
+ private reportError;
7
+ private provideFeedback;
8
+ }
9
+ //# sourceMappingURL=feedback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feedback.d.ts","sourceRoot":"","sources":["../../src/commands/feedback.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,kBAAkB,EACnB,MAAM,qBAAqB,CAAC;AAM7B,qBAAa,QAAS,SAAQ,kBAAkB,CAAC,OAAO,QAAQ,CAAC;IAC/D,SAAS,CAAC,MAAM,CAAC,OAAO,SAAkC;IAEjD,sBAAsB,IAAI,OAAO;IAI3B,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;YA4BrB,WAAW;YAqCX,eAAe;CAqC9B"}
@@ -0,0 +1,95 @@
1
+ import { oclif, prompts, ThymianBaseCommand, } from '@thymian/common-cli';
2
+ import open from 'open';
3
+ import { createEmailReport } from '../create-email-issue-for-error.js';
4
+ import { createGithubIssueUrlForError } from '../create-github-issue-url-for-error.js';
5
+ export class Feedback extends ThymianBaseCommand {
6
+ static CONTACT = 'c3VwcG9ydEB0aHltaWFuLmRldg==';
7
+ shouldSuppressFeedback() {
8
+ return true;
9
+ }
10
+ async run() {
11
+ const lastError = await this.errorCache.read();
12
+ this.log('✨ Thank you for your feedback! ✨');
13
+ this.log();
14
+ if (lastError) {
15
+ this.log(`${oclif.ux.colorize('yellow', '⚠')} It looks like you encountered an error while running the ${oclif.ux.colorize('cyan', lastError.commandName)} command recently.`);
16
+ this.log();
17
+ const reportError = await prompts.confirm({
18
+ message: 'Do you want to report this error?',
19
+ });
20
+ if (reportError) {
21
+ await this.errorCache.reset();
22
+ await this.reportError(lastError);
23
+ }
24
+ else {
25
+ await this.provideFeedback();
26
+ }
27
+ }
28
+ else {
29
+ await this.provideFeedback();
30
+ }
31
+ }
32
+ async reportError(error) {
33
+ const choices = [
34
+ {
35
+ name: 'Via GitHub',
36
+ description: 'Report the error on GitHub via a new issue.',
37
+ value: 'github',
38
+ },
39
+ {
40
+ name: 'Via Email',
41
+ description: 'Contact the Thymian Core team via Email.',
42
+ value: 'email',
43
+ },
44
+ {
45
+ name: 'Not at all ',
46
+ description: "I don't want to report this error.",
47
+ value: 'none',
48
+ },
49
+ ];
50
+ const choice = await prompts.select({
51
+ message: 'How do you want to report this error?',
52
+ choices,
53
+ });
54
+ this.log();
55
+ if (choice === 'github') {
56
+ await open(createGithubIssueUrlForError(error));
57
+ }
58
+ else if (choice === 'email') {
59
+ await open(createEmailReport(Buffer.from(Feedback.CONTACT, 'base64').toString('utf-8'), error));
60
+ }
61
+ }
62
+ async provideFeedback() {
63
+ const choices = [
64
+ {
65
+ name: 'Via GitHub',
66
+ description: 'Open a GitHub issue to provide feedback.',
67
+ value: 'github',
68
+ },
69
+ {
70
+ name: 'Via Email',
71
+ description: 'Contact the Thymian Core team via Email.',
72
+ value: 'email',
73
+ },
74
+ {
75
+ name: 'Not at all ',
76
+ description: "I don't want to give feedback.",
77
+ value: 'none',
78
+ },
79
+ ];
80
+ const choice = await prompts.select({
81
+ message: 'How would you like to provide feedback?',
82
+ choices,
83
+ });
84
+ if (choice === 'github') {
85
+ await open('https://github.com/thymianofficial/thymian/issues/new');
86
+ }
87
+ else if (choice === 'email') {
88
+ const recipient = Buffer.from(Feedback.CONTACT, 'base64').toString('utf-8');
89
+ const subject = 'Thymian CLI Feedback';
90
+ const body = `Hi Support Team,\n\nI'd like to provide some feedback regarding the CLI.\n\n[Please enter your message here]\n\nBest regards,\n[Your Name]`;
91
+ await open(`mailto:${recipient}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`);
92
+ }
93
+ }
94
+ }
95
+ //# sourceMappingURL=feedback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feedback.js","sourceRoot":"","sources":["../../src/commands/feedback.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { ThymianBaseCommand } from '@thymian/common-cli';
2
+ export default class GenerateConfig extends ThymianBaseCommand<typeof GenerateConfig> {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ cwd: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
7
+ interactive: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ output: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
9
+ "for-spec": import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
10
+ };
11
+ run(): Promise<void>;
12
+ private selectSpecInteractive;
13
+ private generateCommentedConfig;
14
+ }
15
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/commands/generate/config.ts"],"names":[],"mappings":"AAIA,OAAO,EAGL,kBAAkB,EACnB,MAAM,qBAAqB,CAAC;AAQ7B,MAAM,CAAC,OAAO,OAAO,cAAe,SAAQ,kBAAkB,CAC5D,OAAO,cAAc,CACtB;IACC,OAAgB,WAAW,SAC+C;IAE1E,OAAgB,QAAQ,WAKtB;IAEF,OAAgB,KAAK;;;;;MAqBnB;IAEW,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;YA2GnB,qBAAqB;IAoDnC,OAAO,CAAC,uBAAuB;CAyBhC"}
@@ -0,0 +1,176 @@
1
+ import { existsSync } from 'node:fs';
2
+ import { writeFile } from 'node:fs/promises';
3
+ import { join, relative } from 'node:path';
4
+ import { defaultConfig, parseSpecFlag, ThymianBaseCommand, } from '@thymian/common-cli';
5
+ import { Flags, ux } from '@thymian/common-cli/oclif';
6
+ import { confirm, input, select } from '@thymian/common-cli/prompts';
7
+ import { stringify } from '@thymian/common-cli/yaml';
8
+ import { searchForOpenApiFiles } from '@thymian/plugin-openapi';
9
+ const DEFAULT_CONFIG_FILENAME = 'thymian.config.yaml';
10
+ export default class GenerateConfig extends ThymianBaseCommand {
11
+ static description = 'Generate a Thymian configuration file for a single API specification.';
12
+ static examples = [
13
+ '<%= config.bin %> generate config',
14
+ '<%= config.bin %> generate config --no-interactive',
15
+ '<%= config.bin %> generate config --output my-api.config.yaml',
16
+ '<%= config.bin %> generate config --for-spec openapi:./petstore.yaml',
17
+ ];
18
+ static flags = {
19
+ cwd: Flags.string({
20
+ default: process.cwd(),
21
+ description: 'Set current working directory.',
22
+ }),
23
+ interactive: Flags.boolean({
24
+ default: true,
25
+ allowNo: true,
26
+ description: 'Run in interactive mode. Use --no-interactive for automation.',
27
+ }),
28
+ output: Flags.string({
29
+ description: 'Output path for the generated configuration file. Defaults to thymian.config.yaml in the working directory.',
30
+ }),
31
+ ['for-spec']: Flags.string({
32
+ multiple: true,
33
+ description: 'Specification input in the format <type>:<location>. Skips auto-detection and uses the provided spec(s) directly.',
34
+ helpValue: 'type:location',
35
+ }),
36
+ };
37
+ async run() {
38
+ const cwd = this.flags.cwd;
39
+ const interactive = this.flags.interactive;
40
+ // Determine output path
41
+ let outputPath = this.flags.output
42
+ ? join(cwd, this.flags.output)
43
+ : join(cwd, DEFAULT_CONFIG_FILENAME);
44
+ // Continuation flow: if default config exists and no explicit output, offer named config
45
+ if (!this.flags.output && existsSync(outputPath)) {
46
+ if (interactive) {
47
+ this.log(`A configuration file already exists at ${outputPath}.`);
48
+ const customPath = await input({
49
+ message: 'Enter a path for the new configuration file (e.g. my-api.config.yaml):',
50
+ });
51
+ if (!customPath) {
52
+ this.error('No path provided. Aborting.', { exit: 1 });
53
+ }
54
+ outputPath = join(cwd, customPath);
55
+ }
56
+ else {
57
+ this.error(`Configuration file already exists at ${outputPath}. Use --output to specify a different path.`, { exit: 1 });
58
+ }
59
+ }
60
+ // Guard against overwriting an existing file at the resolved output path.
61
+ // The default-config-exists case is already handled above; this covers
62
+ // --output pointing to an existing file or an interactive custom path that
63
+ // already exists.
64
+ if (existsSync(outputPath)) {
65
+ if (interactive) {
66
+ const overwrite = await confirm({
67
+ message: `File already exists at ${outputPath}. Overwrite?`,
68
+ default: false,
69
+ });
70
+ if (!overwrite) {
71
+ this.error('Aborted to avoid overwriting existing file.', {
72
+ exit: 1,
73
+ });
74
+ }
75
+ }
76
+ else {
77
+ this.error(`File already exists at ${outputPath}. Use a different --output path or remove the existing file.`, { exit: 1 });
78
+ }
79
+ }
80
+ // Resolve specification: --for-spec flag takes priority over auto-detection
81
+ let selectedSpec;
82
+ if (this.flags['for-spec'] && this.flags['for-spec'].length > 0) {
83
+ // Use the first --for-spec value for the config file
84
+ selectedSpec = parseSpecFlag(this.flags['for-spec'][0]);
85
+ }
86
+ else {
87
+ // Auto-detect OpenAPI files
88
+ const detectedFiles = await searchForOpenApiFiles(cwd);
89
+ if (interactive) {
90
+ const selectedPath = await this.selectSpecInteractive(detectedFiles);
91
+ selectedSpec = { type: 'openapi', location: selectedPath };
92
+ }
93
+ else {
94
+ if (detectedFiles.length === 0) {
95
+ this.error('No OpenAPI/Swagger files detected. Provide a specification manually with --for-spec.', { exit: 1 });
96
+ }
97
+ if (detectedFiles.length === 1) {
98
+ selectedSpec = { type: 'openapi', location: detectedFiles[0] };
99
+ }
100
+ else {
101
+ // In non-interactive mode with multiple specs, use the first one
102
+ selectedSpec = { type: 'openapi', location: detectedFiles[0] };
103
+ this.log(`Multiple specification files detected. Using the first one: ${detectedFiles[0]}`);
104
+ }
105
+ }
106
+ }
107
+ // Build config from defaults
108
+ const config = {
109
+ ...defaultConfig,
110
+ specifications: [selectedSpec],
111
+ };
112
+ // Generate well-commented YAML
113
+ const yamlContent = this.generateCommentedConfig(config, String(selectedSpec.location));
114
+ await writeFile(outputPath, yamlContent, { encoding: 'utf-8' });
115
+ this.log(`${ux.colorize('green', 'Configuration written to')} ${relative(cwd, outputPath)}`);
116
+ }
117
+ async selectSpecInteractive(detectedFiles) {
118
+ if (detectedFiles.length === 0) {
119
+ // No files detected — ask for manual entry
120
+ this.log('No OpenAPI/Swagger specification files detected.');
121
+ const manualPath = await input({
122
+ message: 'Enter the path to your OpenAPI specification file:',
123
+ });
124
+ if (!manualPath) {
125
+ this.error('No specification path provided. Aborting.', { exit: 1 });
126
+ }
127
+ return manualPath;
128
+ }
129
+ if (detectedFiles.length === 1) {
130
+ // Single file — confirm
131
+ const useDetected = await confirm({
132
+ message: `Detected specification: ${detectedFiles[0]}. Use this file?`,
133
+ default: true,
134
+ });
135
+ if (useDetected) {
136
+ return detectedFiles[0];
137
+ }
138
+ // User declined — ask for manual entry
139
+ const manualPath = await input({
140
+ message: 'Enter the path to your OpenAPI specification file:',
141
+ });
142
+ if (!manualPath) {
143
+ this.error('No specification path provided. Aborting.', { exit: 1 });
144
+ }
145
+ return manualPath;
146
+ }
147
+ // Multiple files — selection list
148
+ const selected = await select({
149
+ message: 'Multiple specification files detected. Select one:',
150
+ choices: detectedFiles.map((file) => ({
151
+ name: file,
152
+ value: file,
153
+ })),
154
+ });
155
+ return selected;
156
+ }
157
+ generateCommentedConfig(config, specPath) {
158
+ const yaml = stringify(config);
159
+ // Prepend a comment header explaining the config
160
+ const header = [
161
+ '# Thymian Configuration',
162
+ '# Generated by `thymian generate config`',
163
+ '#',
164
+ `# Specification: ${specPath}`,
165
+ '#',
166
+ '# For documentation, see: https://thymian.dev/docs/configuration',
167
+ '#',
168
+ '# Run `thymian lint` to validate your API specification.',
169
+ '# Run `thymian test` to test a live API against the specification.',
170
+ '#',
171
+ '',
172
+ ].join('\n');
173
+ return header + yaml;
174
+ }
175
+ }
176
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../../src/commands/generate/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import { BaseCliRunCommand } from '@thymian/common-cli';
2
+ export default class Lint extends BaseCliRunCommand<typeof Lint> {
3
+ static description: string;
4
+ static examples: string[];
5
+ run(): Promise<void>;
6
+ }
7
+ //# sourceMappingURL=lint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.d.ts","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EAKlB,MAAM,qBAAqB,CAAC;AAM7B,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,iBAAiB,CAAC,OAAO,IAAI,CAAC;IAC9D,OAAgB,WAAW,SAC+B;IAE1D,OAAgB,QAAQ,WAItB;IAEa,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAwBpC"}
@@ -0,0 +1,24 @@
1
+ import { BaseCliRunCommand, createSeverityRuleFilter, handleWorkflowOutcome, mergeRuleSets, resolveRuleSeverity, } from '@thymian/common-cli';
2
+ export default class Lint extends BaseCliRunCommand {
3
+ static description = 'Lint API specifications against configured rule sets.';
4
+ static examples = [
5
+ '<%= config.bin %> <%= command.id %>',
6
+ '<%= config.bin %> <%= command.id %> --spec openapi:./openapi.yaml',
7
+ '<%= config.bin %> <%= command.id %> --rule-set @thymian/rules-rfc-9110',
8
+ ];
9
+ async run() {
10
+ const specifications = this.thymianConfig.specifications ?? [];
11
+ const ruleSets = mergeRuleSets(this.thymianConfig.ruleSets, this.flags['rule-set']);
12
+ const ruleSeverity = resolveRuleSeverity(this.thymianConfig.ruleSeverity, this.flags['rule-severity']);
13
+ const outcome = await this.thymian.run(async () => {
14
+ return await this.thymian.lint({
15
+ specification: specifications,
16
+ rules: ruleSets,
17
+ rulesConfig: this.thymianConfig.rules,
18
+ ruleFilter: createSeverityRuleFilter(ruleSeverity),
19
+ });
20
+ });
21
+ handleWorkflowOutcome(this, outcome);
22
+ }
23
+ }
24
+ //# sourceMappingURL=lint.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lint.js","sourceRoot":"","sources":["../../src/commands/lint.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EACrB,aAAa,EACb,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAM7B,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,iBAA8B;IAC9D,MAAM,CAAU,WAAW,GACzB,uDAAuD,CAAC;IAE1D,MAAM,CAAU,QAAQ,GAAG;QACzB,qCAAqC;QACrC,mEAAmE;QACnE,wEAAwE;KACzE,CAAC;IAEO,KAAK,CAAC,GAAG;QAChB,MAAM,cAAc,GAAG,IAAI,CAAC,aAAa,CAAC,cAAc,IAAI,EAAE,CAAC;QAE/D,MAAM,QAAQ,GAAG,aAAa,CAC5B,IAAI,CAAC,aAAa,CAAC,QAAQ,EAC3B,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CACvB,CAAC;QAEF,MAAM,YAAY,GAAG,mBAAmB,CACtC,IAAI,CAAC,aAAa,CAAC,YAAY,EAC/B,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAC5B,CAAC;QAEF,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE;YAChD,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;gBAC7B,aAAa,EAAE,cAAc;gBAC7B,KAAK,EAAE,QAAQ;gBACf,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,KAAK;gBACrC,UAAU,EAAE,wBAAwB,CAAC,YAAY,CAAC;aACnD,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,qBAAqB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC"}
@@ -0,0 +1,6 @@
1
+ import { BaseCliRunCommand } from '@thymian/common-cli';
2
+ export default class List extends BaseCliRunCommand<typeof List> {
3
+ static description: string;
4
+ run(): Promise<void>;
5
+ }
6
+ //# sourceMappingURL=list.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../src/commands/plugins/list.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGxD,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,iBAAiB,CAAC,OAAO,IAAI,CAAC;IAC9D,OAAgB,WAAW,SAA0C;IAExD,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAWlC"}
@@ -0,0 +1,14 @@
1
+ import { EOL } from 'node:os';
2
+ import { BaseCliRunCommand } from '@thymian/common-cli';
3
+ import { ux } from '@thymian/common-cli/oclif';
4
+ export default class List extends BaseCliRunCommand {
5
+ static description = 'List all registered Thymian plugins.';
6
+ async run() {
7
+ await this.thymian.run(() => {
8
+ this.log(this.thymian.plugins
9
+ .map((plugin) => ux.colorize(this.config?.theme?.topic, plugin.plugin.name))
10
+ .join(EOL));
11
+ });
12
+ }
13
+ }
14
+ //# sourceMappingURL=list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list.js","sourceRoot":"","sources":["../../../src/commands/plugins/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,SAAS,CAAC;AAE9B,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,EAAE,EAAE,MAAM,2BAA2B,CAAC;AAE/C,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,iBAA8B;IAC9D,MAAM,CAAU,WAAW,GAAG,sCAAsC,CAAC;IAE9D,KAAK,CAAC,GAAG;QACd,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE;YAC1B,IAAI,CAAC,GAAG,CACN,IAAI,CAAC,OAAO,CAAC,OAAO;iBACjB,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CACd,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAC3D;iBACA,IAAI,CAAC,GAAG,CAAC,CACb,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { BaseCliRunCommand } from '@thymian/common-cli';
2
+ export default class GenerateConfigSchema extends BaseCliRunCommand<typeof GenerateConfigSchema> {
3
+ run(): Promise<void>;
4
+ }
5
+ //# sourceMappingURL=schema.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.d.ts","sourceRoot":"","sources":["../../src/commands/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAuB,MAAM,qBAAqB,CAAC;AAM7E,MAAM,CAAC,OAAO,OAAO,oBAAqB,SAAQ,iBAAiB,CACjE,OAAO,oBAAoB,CAC5B;IACgB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAyBpC"}
@@ -0,0 +1,30 @@
1
+ import { BaseCliRunCommand, thymianConfigSchema } from '@thymian/common-cli';
2
+ const configSchema = {
3
+ ...thymianConfigSchema,
4
+ };
5
+ export default class GenerateConfigSchema extends BaseCliRunCommand {
6
+ async run() {
7
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
8
+ // @ts-expect-error
9
+ configSchema.properties.plugins['properties'] = {};
10
+ for (const { plugin } of this.thymian.plugins) {
11
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
12
+ // @ts-expect-error
13
+ configSchema.properties.plugins['properties'][plugin.name] = {
14
+ type: 'object',
15
+ required: ['options'],
16
+ properties: {
17
+ path: {
18
+ type: 'string',
19
+ },
20
+ verbose: {
21
+ type: 'boolean',
22
+ },
23
+ options: plugin.options,
24
+ },
25
+ };
26
+ }
27
+ this.log(JSON.stringify(configSchema, null, 2));
28
+ }
29
+ }
30
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/commands/schema.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAE7E,MAAM,YAAY,GAAG;IACnB,GAAG,mBAAmB;CACvB,CAAC;AAEF,MAAM,CAAC,OAAO,OAAO,oBAAqB,SAAQ,iBAEjD;IACU,KAAK,CAAC,GAAG;QAChB,6DAA6D;QAC7D,mBAAmB;QACnB,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,YAAY,CAAC,GAAG,EAAE,CAAC;QAEnD,KAAK,MAAM,EAAE,MAAM,EAAE,IAAI,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;YAC9C,6DAA6D;YAC7D,mBAAmB;YACnB,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG;gBAC3D,IAAI,EAAE,QAAQ;gBACd,QAAQ,EAAE,CAAC,SAAS,CAAC;gBACrB,UAAU,EAAE;oBACV,IAAI,EAAE;wBACJ,IAAI,EAAE,QAAQ;qBACf;oBACD,OAAO,EAAE;wBACP,IAAI,EAAE,SAAS;qBAChB;oBACD,OAAO,EAAE,MAAM,CAAC,OAAO;iBACxB;aACF,CAAC;QACJ,CAAC;QAED,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;IAClD,CAAC;CACF"}
@@ -0,0 +1,8 @@
1
+ import { BaseCliRunCommand } from '@thymian/common-cli';
2
+ export default class Serve extends BaseCliRunCommand<typeof Serve> {
3
+ static description: string;
4
+ static examples: string[];
5
+ static requiresSpecifications: boolean;
6
+ run(): Promise<void>;
7
+ }
8
+ //# sourceMappingURL=serve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve.d.ts","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,CAAC,OAAO,OAAO,KAAM,SAAQ,iBAAiB,CAAC,OAAO,KAAK,CAAC;IAChE,OAAgB,WAAW,SAAgC;IAC3D,OAAgB,QAAQ,WAA2C;IACnE,OAAgB,sBAAsB,UAAS;IAEhC,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CAiCpC"}
@@ -0,0 +1,31 @@
1
+ import { BaseCliRunCommand } from '@thymian/common-cli';
2
+ export default class Serve extends BaseCliRunCommand {
3
+ static description = 'Run Thymian in serve mode.';
4
+ static examples = ['<%= config.bin %> <%= command.id %>'];
5
+ static requiresSpecifications = false;
6
+ async run() {
7
+ const close = async (code = 0) => {
8
+ this.debug('Closing Thymian.');
9
+ await this.thymian.close();
10
+ process.exit(code);
11
+ };
12
+ process.on('SIGINT', close);
13
+ this.thymian.emitter.on('core.exit', async ({ code }) => {
14
+ await this.thymian.close();
15
+ await close(code);
16
+ });
17
+ const quit = 'q';
18
+ if (process.stdin.isTTY) {
19
+ process.stdin.setRawMode(true);
20
+ }
21
+ process.stdin.resume();
22
+ process.stdin.on('data', async (data) => {
23
+ if (data.toString() === quit) {
24
+ await close(0);
25
+ }
26
+ });
27
+ await this.thymian.ready();
28
+ this.log(`Thymian is now in "serve" mode. Press "${quit}" to exit.`);
29
+ }
30
+ }
31
+ //# sourceMappingURL=serve.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serve.js","sourceRoot":"","sources":["../../src/commands/serve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,CAAC,OAAO,OAAO,KAAM,SAAQ,iBAA+B;IAChE,MAAM,CAAU,WAAW,GAAG,4BAA4B,CAAC;IAC3D,MAAM,CAAU,QAAQ,GAAG,CAAC,qCAAqC,CAAC,CAAC;IACnE,MAAM,CAAU,sBAAsB,GAAG,KAAK,CAAC;IAEtC,KAAK,CAAC,GAAG;QAChB,MAAM,KAAK,GAAG,KAAK,EAAE,IAAI,GAAG,CAAC,EAAE,EAAE;YAC/B,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;YAE/B,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAE3B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC,CAAC;QAEF,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;QAE5B,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,WAAW,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE;YACtD,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAE3B,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,GAAG,CAAC;QAEjB,IAAI,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;YACxB,OAAO,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QACjC,CAAC;QACD,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;QACvB,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE,EAAE;YACtC,IAAI,IAAI,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE,CAAC;gBAC7B,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC;YACjB,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;QAE3B,IAAI,CAAC,GAAG,CAAC,0CAA0C,IAAI,YAAY,CAAC,CAAC;IACvE,CAAC"}
@@ -0,0 +1,10 @@
1
+ import { BaseCliRunCommand } from '@thymian/common-cli';
2
+ export default class Test extends BaseCliRunCommand<typeof Test> {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ "target-url": import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ };
8
+ run(): Promise<void>;
9
+ }
10
+ //# sourceMappingURL=test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../src/commands/test.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EAKlB,MAAM,qBAAqB,CAAC;AAO7B,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,iBAAiB,CAAC,OAAO,IAAI,CAAC;IAC9D,OAAgB,WAAW,SACwD;IAEnF,OAAgB,QAAQ,WAKtB;IAEF,OAAgB,KAAK;;MAKnB;IAEa,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;CA2BpC"}
@@ -0,0 +1,33 @@
1
+ import { BaseCliRunCommand, createSeverityRuleFilter, handleWorkflowOutcome, mergeRuleSets, resolveRuleSeverity, } from '@thymian/common-cli';
2
+ import { Flags } from '@thymian/common-cli/oclif';
3
+ export default class Test extends BaseCliRunCommand {
4
+ static description = 'Test API specifications by running live requests against configured rule sets.';
5
+ static examples = [
6
+ '<%= config.bin %> <%= command.id %>',
7
+ '<%= config.bin %> <%= command.id %> --spec openapi:./openapi.yaml',
8
+ '<%= config.bin %> <%= command.id %> --rule-set @thymian/rules-rfc-9110',
9
+ '<%= config.bin %> <%= command.id %> --target-url http://localhost:8080',
10
+ ];
11
+ static flags = {
12
+ ['target-url']: Flags.string({
13
+ description: 'Override the target URL for all test requests. When set, all requests are sent to this origin instead of the servers defined in the specification.',
14
+ }),
15
+ };
16
+ async run() {
17
+ const specifications = this.thymianConfig.specifications ?? [];
18
+ const ruleSets = mergeRuleSets(this.thymianConfig.ruleSets, this.flags['rule-set']);
19
+ const ruleSeverity = resolveRuleSeverity(this.thymianConfig.ruleSeverity, this.flags['rule-severity']);
20
+ const targetUrl = this.flags['target-url'] ?? this.thymianConfig.targetUrl;
21
+ const outcome = await this.thymian.run(async () => {
22
+ return await this.thymian.test({
23
+ specification: specifications,
24
+ rules: ruleSets,
25
+ rulesConfig: this.thymianConfig.rules,
26
+ ruleFilter: createSeverityRuleFilter(ruleSeverity),
27
+ targetUrl,
28
+ });
29
+ });
30
+ handleWorkflowOutcome(this, outcome);
31
+ }
32
+ }
33
+ //# sourceMappingURL=test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test.js","sourceRoot":"","sources":["../../src/commands/test.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,wBAAwB,EACxB,qBAAqB,EACrB,aAAa,EACb,mBAAmB,GACpB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EAAE,KAAK,EAAE,MAAM,2BAA2B,CAAC;AAMlD,MAAM,CAAC,OAAO,OAAO,IAAK,SAAQ,iBAA8B;IAC9D,MAAM,CAAU,WAAW,GACzB,gFAAgF,CAAC;IAEnF,MAAM,CAAU,QAAQ,GAAG;QACzB,qCAAqC;QACrC,mEAAmE;QACnE,wEAAwE;QACxE,wEAAwE;KACzE,CAAC;IAEF,MAAM,CAAU,KAAK,GAAG;QACtB,CAAC,YAAY,CAAC,EAAE,KAAK,CAAC,MAAM,CAAC;YAC3B,WAAW,EACT,oJAAoJ;SACvJ,CAAC;KACH,CAAC;IAEO,KAAK,CAAC,GAAG;QAChB,MAAM,cAAc,GAAG,IAAI,CAAC,aAAa,CAAC,cAAc,IAAI,EAAE,CAAC;QAE/D,MAAM,QAAQ,GAAG,aAAa,CAC5B,IAAI,CAAC,aAAa,CAAC,QAAQ,EAC3B,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CACvB,CAAC;QAEF,MAAM,YAAY,GAAG,mBAAmB,CACtC,IAAI,CAAC,aAAa,CAAC,YAAY,EAC/B,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAC5B,CAAC;QAEF,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC;QAE3E,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE;YAChD,OAAO,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC;gBAC7B,aAAa,EAAE,cAAc;gBAC7B,KAAK,EAAE,QAAQ;gBACf,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,KAAK;gBACrC,UAAU,EAAE,wBAAwB,CAAC,YAAY,CAAC;gBAClD,SAAS;aACV,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,qBAAqB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { CachedError } from '@thymian/common-cli';
2
+ export declare function createEmailReport(recipient: string, errorData: CachedError): string;
3
+ //# sourceMappingURL=create-email-issue-for-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-email-issue-for-error.d.ts","sourceRoot":"","sources":["../src/create-email-issue-for-error.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,WAAW,GACrB,MAAM,CAiCR"}
@@ -0,0 +1,31 @@
1
+ export function createEmailReport(recipient, errorData) {
2
+ const subject = `CLI Error Report: ${errorData.commandName}`;
3
+ const body = `
4
+ Hi Support Team,
5
+
6
+ I'd like to provide some feedback regarding the CLI.
7
+
8
+ ${errorData
9
+ ? `--- ERROR REPORT ---
10
+ Command: ${errorData.commandName}
11
+ Timestamp: ${new Date(errorData.timestamp).toLocaleString()}
12
+
13
+ ENVIRONMENT:
14
+ - CLI: ${errorData.version.cliVersion}
15
+ - Node: ${errorData.version.nodeVersion}
16
+ - OS: ${errorData.version.osVersion} (${errorData.version.architecture})
17
+
18
+ PLUGINS:
19
+ ${errorData.pluginVersions.map((p) => ` - ${p.name}: ${p.version}`).join('\n')}
20
+
21
+ STACKTRACE:
22
+ ${errorData.stack?.replaceAll(process.env.HOME || '', '~') || 'No stacktrace available'}
23
+ --------------------`
24
+ : 'Description of my feedback:\n\n[Please enter your message here]'}
25
+
26
+ Best regards,
27
+ [Your Name]
28
+ `.trim();
29
+ return `mailto:${recipient}?subject=${encodeURIComponent(subject)}&body=${encodeURIComponent(body)}`;
30
+ }
31
+ //# sourceMappingURL=create-email-issue-for-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-email-issue-for-error.js","sourceRoot":"","sources":["../src/create-email-issue-for-error.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,iBAAiB,CAC/B,SAAiB,EACjB,SAAsB;IAEtB,MAAM,OAAO,GAAG,qBAAqB,SAAS,CAAC,WAAW,EAAE,CAAC;IAE7D,MAAM,IAAI,GAAG;;;;;EAMb,SAAS;QACP,CAAC,CAAC;WACK,SAAS,CAAC,WAAW;aACnB,IAAI,IAAI,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC,cAAc,EAAE;;;SAGlD,SAAS,CAAC,OAAO,CAAC,UAAU;UAC3B,SAAS,CAAC,OAAO,CAAC,WAAW;QAC/B,SAAS,CAAC,OAAO,CAAC,SAAS,KAAK,SAAS,CAAC,OAAO,CAAC,YAAY;;;EAGpE,SAAS,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,IAAI,KAAK,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;EAG7E,SAAS,CAAC,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,GAAG,CAAC,IAAI,yBAAyB;qBAClE;QACjB,CAAC,CAAC,iEACN;;;;CAIC,CAAC,IAAI,EAAE,CAAC;IAEP,OAAO,UAAU,SAAS,YAAY,kBAAkB,CAAC,OAAO,CAAC,SAAS,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;AACvG,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { CachedError } from '@thymian/common-cli';
2
+ export declare function createGithubIssueUrlForError(error: CachedError): string;
3
+ //# sourceMappingURL=create-github-issue-url-for-error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-github-issue-url-for-error.d.ts","sourceRoot":"","sources":["../src/create-github-issue-url-for-error.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAEvD,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAmDvE"}
@@ -0,0 +1,45 @@
1
+ export function createGithubIssueUrlForError(error) {
2
+ const baseUrl = 'https://github.com/thymianofficial/thymian/issues/new';
3
+ const title = `${error.name} while running in command \`${error.commandName}\``;
4
+ const pluginTable = error?.pluginVersions
5
+ .map((p) => `| ${p.name} | ${p.version} |`)
6
+ .join('\n') || '| none | - |';
7
+ const body = `
8
+ ### 📝 Description
9
+ ### 💻 Environment
10
+ - **CLI Version:** \`${error.version.cliVersion || 'N/A'}\`
11
+ - **Node Version:** \`${error.version.nodeVersion || 'N/A'}\`
12
+ - **OS:** \`${error?.version.osVersion || 'N/A'}\` (${error.version.architecture})
13
+ - **Command:** \`${error?.commandName} || ''}\`
14
+ - **Timestamp:** ${error ? new Date(error.timestamp).toLocaleString() : 'N/A'}
15
+
16
+ <details>
17
+ <summary><b>🔌 Installed Plugins</b></summary>
18
+
19
+ | Plugin | Version |
20
+ | :--- | :--- |
21
+ ${pluginTable}
22
+ </details>
23
+
24
+ ### 🔍 Error Details
25
+ ${error.stack
26
+ ? `
27
+ <details>
28
+ <summary><b>Click to expand Stacktrace</b></summary>
29
+
30
+ \`\`\`text
31
+ ${error.stack.replaceAll(process.env.HOME || '', '~')}
32
+ \`\`\`
33
+ </details>
34
+ `
35
+ : '_No stacktrace available._'}
36
+
37
+ ---
38
+ *Reported via \`thymian feedback\`*`.trim();
39
+ const url = new URL(baseUrl);
40
+ url.searchParams.set('title', title);
41
+ url.searchParams.set('body', body);
42
+ url.searchParams.set('labels', 'bug');
43
+ return url.toString();
44
+ }
45
+ //# sourceMappingURL=create-github-issue-url-for-error.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-github-issue-url-for-error.js","sourceRoot":"","sources":["../src/create-github-issue-url-for-error.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,4BAA4B,CAAC,KAAkB;IAC7D,MAAM,OAAO,GAAG,uDAAuD,CAAC;IAExE,MAAM,KAAK,GAAG,GAAG,KAAK,CAAC,IAAI,+BAA+B,KAAK,CAAC,WAAW,IAAI,CAAC;IAEhF,MAAM,WAAW,GACf,KAAK,EAAE,cAAc;SAClB,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,IAAI,MAAM,CAAC,CAAC,OAAO,IAAI,CAAC;SAC1C,IAAI,CAAC,IAAI,CAAC,IAAI,cAAc,CAAC;IAElC,MAAM,IAAI,GAAG;;;uBAGQ,KAAK,CAAC,OAAO,CAAC,UAAU,IAAI,KAAK;wBAChC,KAAK,CAAC,OAAO,CAAC,WAAW,IAAI,KAAK;cAC5C,KAAK,EAAE,OAAO,CAAC,SAAS,IAAI,KAAK,OAAO,KAAK,CAAC,OAAO,CAAC,YAAY;mBAC7D,KAAK,EAAE,WAAW;mBAClB,KAAK,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,KAAK;;;;;;;EAO3E,WAAW;;;;EAKX,KAAK,CAAC,KAAK;QACT,CAAC,CAAC;;;;;EAKJ,KAAK,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,EAAE,EAAE,GAAG,CAAC;;;CAGpD;QACG,CAAC,CAAC,4BACN;;;oCAGoC,CAAC,IAAI,EAAE,CAAC;IAE1C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;IAC7B,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;IACrC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IACnC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;IAEtC,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import { type ThymianFeedbackHook } from '@thymian/common-cli';
2
+ declare const hook: ThymianFeedbackHook;
3
+ export default hook;
4
+ //# sourceMappingURL=feedback.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feedback.d.ts","sourceRoot":"","sources":["../../src/hooks/feedback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,KAAK,mBAAmB,EAAE,MAAM,qBAAqB,CAAC;AAEtE,QAAA,MAAM,IAAI,EAAE,mBAKX,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { oclif } from '@thymian/common-cli';
2
+ const hook = async () => {
3
+ const message = `${oclif.ux.colorize('blueBright', `🚀 Tip: Found a bug or wanna give feedback? Run ${oclif.ux.colorize('bold', 'thymian feedback')}.`)}`;
4
+ console.log(message);
5
+ console.log();
6
+ };
7
+ export default hook;
8
+ //# sourceMappingURL=feedback.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"feedback.js","sourceRoot":"","sources":["../../src/hooks/feedback.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAA4B,MAAM,qBAAqB,CAAC;AAEtE,MAAM,IAAI,GAAwB,KAAK,IAAI,EAAE;IAC3C,MAAM,OAAO,GAAG,GAAG,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,YAAY,EAAE,oDAAoD,KAAK,CAAC,EAAE,CAAC,QAAQ,CAAC,MAAM,EAAE,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC;IAE3J,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACrB,OAAO,CAAC,GAAG,EAAE,CAAC;AAChB,CAAC,CAAC;AAEF,eAAe,IAAI,CAAC"}
package/package.json CHANGED
@@ -1,11 +1,65 @@
1
1
  {
2
2
  "name": "thymian",
3
- "version": "0.0.1",
4
- "description": "",
5
- "main": "index.js",
6
- "scripts": {
7
- "test": "echo \"Error: no test specified\" && exit 1"
8
- },
9
- "author": "",
10
- "license": "ISC"
3
+ "version": "0.1.0",
4
+ "license": "AGPL-3.0-only",
5
+ "publishConfig": {
6
+ "access": "public"
7
+ },
8
+ "main": "./dist/index.js",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "type": "module",
12
+ "exports": {
13
+ "./package.json": "./package.json",
14
+ ".": {
15
+ "types": "./dist/index.d.ts",
16
+ "import": "./dist/index.js",
17
+ "default": "./dist/index.js"
18
+ }
19
+ },
20
+ "files": [
21
+ "dist",
22
+ "!**/*.tsbuildinfo"
23
+ ],
24
+ "dependencies": {
25
+ "@oclif/plugin-help": "^6.2.29",
26
+ "@oclif/plugin-not-found": "^3.2.57",
27
+ "@oclif/plugin-plugins": "^5.4.43",
28
+ "@oclif/plugin-version": "^2.2.30",
29
+ "@thymian/common-cli": "0.1.0",
30
+ "@thymian/plugin-http-analyzer": "0.1.0",
31
+ "@thymian/plugin-http-linter": "0.1.0",
32
+ "@thymian/plugin-http-tester": "0.1.0",
33
+ "@thymian/plugin-openapi": "0.1.0",
34
+ "@thymian/plugin-reporter": "0.1.0",
35
+ "@thymian/plugin-request-dispatcher": "0.1.0",
36
+ "@thymian/plugin-sampler": "0.1.0",
37
+ "@thymian/plugin-websocket-proxy": "0.1.0",
38
+ "@thymian/rules-rfc-9110": "0.1.0",
39
+ "open": "^8.4.2",
40
+ "tslib": "^2.3.0"
41
+ },
42
+ "bin": {
43
+ "thymian": "./bin/run.js"
44
+ },
45
+ "oclif": {
46
+ "bin": "thymian",
47
+ "commands": "./dist/commands",
48
+ "hooks": {
49
+ "thymian.feedback": "./dist/hooks/feedback"
50
+ },
51
+ "dirname": "thymian",
52
+ "topicSeparator": " ",
53
+ "plugins": [
54
+ "@oclif/plugin-help",
55
+ "@oclif/plugin-not-found",
56
+ "@oclif/plugin-version",
57
+ "@thymian/plugin-http-linter"
58
+ ]
59
+ },
60
+ "devDependencies": {
61
+ "@oclif/test": "^4.1.13",
62
+ "@types/node": "^18.19.112",
63
+ "tsx": "^4.20.3"
64
+ }
11
65
  }