prodex 2.0.0 → 2.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 (119) hide show
  1. package/README.md +369 -146
  2. package/dist/app/dependency-source-provider.d.ts +2 -0
  3. package/dist/app/dependency-source-provider.js +66 -0
  4. package/dist/app/entry-resolver.d.ts +7 -0
  5. package/dist/app/entry-resolver.js +26 -0
  6. package/dist/app/execute-run.d.ts +2 -2
  7. package/dist/app/execute-run.js +138 -36
  8. package/dist/app/git-source-provider.d.ts +4 -0
  9. package/dist/app/git-source-provider.js +551 -0
  10. package/dist/app/grep-source-provider.d.ts +2 -0
  11. package/dist/app/grep-source-provider.js +226 -0
  12. package/dist/app/planner.d.ts +12 -0
  13. package/dist/app/planner.js +106 -0
  14. package/dist/app/planners/attachment-options.d.ts +2 -0
  15. package/dist/app/planners/attachment-options.js +39 -0
  16. package/dist/app/planners/git-plan.d.ts +13 -0
  17. package/dist/app/planners/git-plan.js +141 -0
  18. package/dist/app/planners/grep-plan.d.ts +13 -0
  19. package/dist/app/planners/grep-plan.js +115 -0
  20. package/dist/app/planners/list-utils.d.ts +1 -0
  21. package/dist/app/planners/list-utils.js +6 -0
  22. package/dist/app/planners/pack-plan.d.ts +13 -0
  23. package/dist/app/planners/pack-plan.js +65 -0
  24. package/dist/app/planners/scope-plan.d.ts +17 -0
  25. package/dist/app/planners/scope-plan.js +143 -0
  26. package/dist/app/planners/trace-plan.d.ts +13 -0
  27. package/dist/app/planners/trace-plan.js +77 -0
  28. package/dist/app/source-collector.d.ts +5 -0
  29. package/dist/app/source-collector.js +33 -0
  30. package/dist/app/target-resolver.d.ts +7 -0
  31. package/dist/app/target-resolver.js +110 -0
  32. package/dist/cli/cli-input.js +70 -19
  33. package/dist/cli/flag-specs.d.ts +7 -3
  34. package/dist/cli/flag-specs.js +58 -7
  35. package/dist/cli/help-specs.d.ts +205 -0
  36. package/dist/cli/help-specs.js +136 -0
  37. package/dist/cli/help.js +107 -28
  38. package/dist/cli/report-command.js +59 -26
  39. package/dist/commands/{run-command.d.ts → git-command.d.ts} +3 -3
  40. package/dist/commands/git-command.js +7 -0
  41. package/dist/commands/grep-command.d.ts +11 -0
  42. package/dist/commands/grep-command.js +7 -0
  43. package/dist/commands/pack-command.d.ts +11 -0
  44. package/dist/commands/pack-command.js +7 -0
  45. package/dist/commands/scope-command.d.ts +12 -0
  46. package/dist/commands/scope-command.js +7 -0
  47. package/dist/commands/shared-runner.d.ts +12 -0
  48. package/dist/commands/shared-runner.js +30 -0
  49. package/dist/commands/trace-command.d.ts +11 -0
  50. package/dist/commands/trace-command.js +7 -0
  51. package/dist/config/default-config.js +7 -11
  52. package/dist/config/load.d.ts +1 -0
  53. package/dist/config/load.js +269 -4
  54. package/dist/config/migration/detect.d.ts +2 -1
  55. package/dist/config/migration/detect.js +10 -2
  56. package/dist/config/migration/messages.js +12 -11
  57. package/dist/config/migration/transform.js +77 -32
  58. package/dist/filesystem/binary.d.ts +2 -0
  59. package/dist/filesystem/binary.js +30 -0
  60. package/dist/filesystem/entry-discovery.d.ts +14 -0
  61. package/dist/filesystem/entry-discovery.js +78 -0
  62. package/dist/filesystem/file-set.d.ts +7 -0
  63. package/dist/filesystem/file-set.js +57 -0
  64. package/dist/filesystem/glob-scan.d.ts +6 -2
  65. package/dist/filesystem/glob-scan.js +12 -7
  66. package/dist/filesystem/path-patterns.d.ts +20 -0
  67. package/dist/filesystem/path-patterns.js +70 -0
  68. package/dist/index.js +51 -29
  69. package/dist/output/markdown-sections.d.ts +5 -0
  70. package/dist/output/markdown-sections.js +103 -0
  71. package/dist/output/markdown-toc.d.ts +31 -0
  72. package/dist/output/markdown-toc.js +287 -0
  73. package/dist/output/markdown.d.ts +5 -8
  74. package/dist/output/markdown.js +80 -127
  75. package/dist/output/produce-output.d.ts +4 -1
  76. package/dist/output/produce-output.js +6 -7
  77. package/dist/output/render-helpers.d.ts +4 -0
  78. package/dist/output/render-helpers.js +14 -0
  79. package/dist/output/text.d.ts +2 -2
  80. package/dist/output/text.js +47 -8
  81. package/dist/resolvers/js/resolve-alias.js +10 -41
  82. package/dist/resolvers/php/bindings.js +6 -6
  83. package/dist/resolvers/php/extract-imports.d.ts +19 -7
  84. package/dist/resolvers/php/extract-imports.js +146 -26
  85. package/dist/resolvers/php/php-resolver.js +55 -24
  86. package/dist/resolvers/php/psr4.d.ts +1 -1
  87. package/dist/resolvers/php/psr4.js +7 -1
  88. package/dist/runtime/shell-command-runner.d.ts +5 -0
  89. package/dist/runtime/shell-command-runner.js +118 -0
  90. package/dist/tracing/collect-trace.d.ts +10 -0
  91. package/dist/tracing/collect-trace.js +23 -0
  92. package/dist/tracing/exclude.d.ts +0 -5
  93. package/dist/tracing/exclude.js +16 -12
  94. package/dist/tracing/follow-chain.js +2 -2
  95. package/dist/types/app.types.d.ts +38 -8
  96. package/dist/types/artifact.types.d.ts +50 -0
  97. package/dist/types/artifact.types.js +2 -0
  98. package/dist/types/cli.types.d.ts +52 -4
  99. package/dist/types/config.types.d.ts +37 -20
  100. package/dist/types/index.d.ts +2 -0
  101. package/dist/types/index.js +2 -0
  102. package/dist/types/output.types.d.ts +12 -3
  103. package/dist/types/planner.types.d.ts +76 -0
  104. package/dist/types/planner.types.js +2 -0
  105. package/dist/types/resolver.types.d.ts +1 -1
  106. package/dist/types/tracing.types.d.ts +0 -11
  107. package/package.json +2 -2
  108. package/schema/prodex.schema.json +59 -41
  109. package/dist/app/run-plans.d.ts +0 -11
  110. package/dist/app/run-plans.js +0 -61
  111. package/dist/commands/profiles-command.d.ts +0 -6
  112. package/dist/commands/profiles-command.js +0 -16
  113. package/dist/commands/run-command.js +0 -17
  114. package/dist/config/build-config.d.ts +0 -13
  115. package/dist/config/build-config.js +0 -127
  116. package/dist/tracing/include-files.d.ts +0 -2
  117. package/dist/tracing/include-files.js +0 -36
  118. package/dist/tracing/trace-run.d.ts +0 -2
  119. package/dist/tracing/trace-run.js +0 -21
@@ -0,0 +1,13 @@
1
+ import type { ExecutionPlan, CommandIntent, ProdexConfigFile, CommandAttachmentOptions } from "../../types";
2
+ export declare function buildPackPlan(params: {
3
+ intent: CommandIntent;
4
+ userConfig: ProdexConfigFile;
5
+ root: string;
6
+ aliases: Record<string, string>;
7
+ depth: number;
8
+ maxFiles: number;
9
+ defaultOutput: ExecutionPlan["output"];
10
+ attachmentOptions: CommandAttachmentOptions | undefined;
11
+ warnings: string[];
12
+ errors: string[];
13
+ }): ExecutionPlan[];
@@ -0,0 +1,65 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildPackPlan = buildPackPlan;
4
+ const path_patterns_1 = require("../../filesystem/path-patterns");
5
+ const list_utils_1 = require("./list-utils");
6
+ function buildPackPlan(params) {
7
+ const { intent, userConfig, root, aliases, depth, maxFiles, defaultOutput, attachmentOptions, warnings, errors } = params;
8
+ const flags = intent.flags ?? {};
9
+ // Validation
10
+ if (flags.key !== undefined || flags.all !== undefined || flags.list !== undefined) {
11
+ errors.push('Command "pack" does not accept "--key", "--all", or "--list".');
12
+ return [];
13
+ }
14
+ const hasCliEntry = flags.entry && flags.entry.length > 0;
15
+ const hasCliInclude = flags.include && flags.include.length > 0;
16
+ const hasCliScope = flags.scope && flags.scope.length > 0;
17
+ if (!hasCliEntry && !hasCliInclude && !hasCliScope) {
18
+ errors.push('Command "pack" requires at least one source: --entry, --include, or --scope.');
19
+ return [];
20
+ }
21
+ const rootExclude = userConfig.exclude ?? [];
22
+ const scopeEntries = [];
23
+ const scopeIncludes = [];
24
+ const scopeExcludes = [];
25
+ if (flags.scope && flags.scope.length > 0) {
26
+ for (const scopeKey of flags.scope) {
27
+ const scope = userConfig.scopes?.[scopeKey];
28
+ if (!scope) {
29
+ errors.push(`Unknown scope "${scopeKey}".`);
30
+ return [];
31
+ }
32
+ if (scope.entry)
33
+ scopeEntries.push(...scope.entry);
34
+ if (scope.include)
35
+ scopeIncludes.push(...scope.include);
36
+ if (scope.exclude)
37
+ scopeExcludes.push(...scope.exclude);
38
+ }
39
+ }
40
+ const mergedEntry = [...scopeEntries, ...(flags.entry ?? [])].map((item) => (0, path_patterns_1.normalizePathOrGlob)(item, root, { role: "entry" }));
41
+ const mergedInclude = [...scopeIncludes, ...(flags.include ?? [])].map((item) => (0, path_patterns_1.normalizePathOrGlob)(item, root, { role: "include" }));
42
+ const mergedExclude = [...rootExclude, ...scopeExcludes, ...(flags.exclude ?? [])].map((item) => (0, path_patterns_1.normalizePathOrGlob)(item, root, { role: "exclude" }));
43
+ if (errors.length) {
44
+ return [];
45
+ }
46
+ const plan = {
47
+ root,
48
+ command: "pack",
49
+ outputName: flags.name ?? "pack-combined",
50
+ entry: (0, list_utils_1.uniqueTrimmed)(mergedEntry),
51
+ include: (0, list_utils_1.uniqueTrimmed)(mergedInclude),
52
+ exclude: (0, list_utils_1.uniqueTrimmed)(mergedExclude),
53
+ depth: flags.depth ?? depth,
54
+ maxFiles: flags.maxFiles ?? maxFiles,
55
+ aliases,
56
+ output: {
57
+ dir: defaultOutput.dir,
58
+ versioned: defaultOutput.versioned,
59
+ format: flags.format ?? defaultOutput.format,
60
+ },
61
+ dryRun: !!flags.dryRun,
62
+ attachmentOptions,
63
+ };
64
+ return [plan];
65
+ }
@@ -0,0 +1,17 @@
1
+ import type { ExecutionPlan, CommandIntent, ProdexConfigFile, CommandAttachmentOptions } from "../../types";
2
+ export interface ScopePlanResult {
3
+ plans: ExecutionPlan[];
4
+ listScopes?: string[];
5
+ }
6
+ export declare function buildScopePlan(params: {
7
+ intent: CommandIntent;
8
+ userConfig: ProdexConfigFile;
9
+ root: string;
10
+ aliases: Record<string, string>;
11
+ depth: number;
12
+ maxFiles: number;
13
+ defaultOutput: ExecutionPlan["output"];
14
+ attachmentOptions: CommandAttachmentOptions | undefined;
15
+ warnings: string[];
16
+ errors: string[];
17
+ }): ScopePlanResult;
@@ -0,0 +1,143 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildScopePlan = buildScopePlan;
4
+ const path_patterns_1 = require("../../filesystem/path-patterns");
5
+ const list_utils_1 = require("./list-utils");
6
+ function buildScopePlan(params) {
7
+ const { intent, userConfig, root, aliases, depth, maxFiles, defaultOutput, attachmentOptions, warnings, errors } = params;
8
+ const flags = intent.flags ?? {};
9
+ // Validation
10
+ if (flags.entry !== undefined ||
11
+ flags.include !== undefined ||
12
+ flags.scope !== undefined ||
13
+ flags.name !== undefined ||
14
+ flags.depth !== undefined ||
15
+ flags.maxFiles !== undefined) {
16
+ errors.push('Command "scope" does not accept "--entry", "--include", "--scope", "--name", "--depth", or "--max-files".');
17
+ return { plans: [] };
18
+ }
19
+ const hasKey = flags.key && flags.key.length > 0;
20
+ const hasAll = !!flags.all;
21
+ const hasList = !!flags.list;
22
+ if (!hasKey && !hasAll && !hasList) {
23
+ errors.push('Command "scope" requires specifying "-k/--key", "--all", or "--list".');
24
+ return { plans: [] };
25
+ }
26
+ let selectedModesCount = 0;
27
+ if (hasKey)
28
+ selectedModesCount++;
29
+ if (hasAll)
30
+ selectedModesCount++;
31
+ if (hasList)
32
+ selectedModesCount++;
33
+ if (selectedModesCount > 1) {
34
+ errors.push('Command "scope" options "--key", "--all", and "--list" are mutually exclusive.');
35
+ return { plans: [] };
36
+ }
37
+ const availableScopes = Object.keys(userConfig.scopes ?? {}).sort();
38
+ if (hasList) {
39
+ if ((flags.cmd && flags.cmd.length > 0) || flags.cmdTimeout !== undefined || flags.failOnCmdError !== undefined) {
40
+ errors.push('Option "--list" cannot be used with command attachment options.');
41
+ return { plans: [] };
42
+ }
43
+ return { plans: [], listScopes: availableScopes };
44
+ }
45
+ if (errors.length) {
46
+ return { plans: [] };
47
+ }
48
+ let targetKeys = [];
49
+ if (hasAll) {
50
+ targetKeys = availableScopes;
51
+ if (!targetKeys.length) {
52
+ errors.push("No scopes are defined in prodex.json.");
53
+ return { plans: [] };
54
+ }
55
+ }
56
+ else if (flags.key) {
57
+ for (const key of flags.key) {
58
+ if (!userConfig.scopes?.[key]) {
59
+ errors.push(`Unknown scope "${key}".`);
60
+ return { plans: [] };
61
+ }
62
+ targetKeys.push(key);
63
+ }
64
+ }
65
+ const plans = [];
66
+ for (const key of targetKeys) {
67
+ const scope = userConfig.scopes[key];
68
+ const scopeIncludes = (scope.include ?? []).map((item) => (0, path_patterns_1.normalizePathOrGlob)(item, root, { role: "include" }));
69
+ const scopeExcludes = [...(userConfig.exclude ?? []), ...(scope.exclude ?? []), ...(flags.exclude ?? [])].map((item) => (0, path_patterns_1.normalizePathOrGlob)(item, root, { role: "exclude" }));
70
+ if (scope.grep) {
71
+ let grepMode = "query";
72
+ let grepTerms = [];
73
+ if (scope.grep.query !== undefined) {
74
+ grepMode = "query";
75
+ grepTerms = [scope.grep.query];
76
+ }
77
+ else if (scope.grep.any !== undefined) {
78
+ grepMode = "any";
79
+ grepTerms = scope.grep.any;
80
+ }
81
+ else if (scope.grep.all !== undefined) {
82
+ grepMode = "all";
83
+ grepTerms = scope.grep.all;
84
+ }
85
+ else if (scope.grep.regex !== undefined) {
86
+ grepMode = "regex";
87
+ grepTerms = [scope.grep.regex];
88
+ }
89
+ const negativeTerms = scope.grep.not ?? [];
90
+ const mergedWithin = (scope.grep.within ?? []).map((item) => (0, path_patterns_1.normalizePathOrGlob)(item, root, { role: "within" }));
91
+ const mergedSkip = (scope.grep.skip ?? []).map((item) => (0, path_patterns_1.normalizePathOrGlob)(item, root, { role: "skip" }));
92
+ plans.push({
93
+ root,
94
+ command: "scope",
95
+ outputName: scope.name ?? key,
96
+ entry: [],
97
+ include: scopeIncludes,
98
+ exclude: (0, list_utils_1.uniqueTrimmed)(scopeExcludes),
99
+ depth,
100
+ maxFiles,
101
+ aliases,
102
+ output: {
103
+ dir: defaultOutput.dir,
104
+ versioned: defaultOutput.versioned,
105
+ format: flags.format ?? defaultOutput.format,
106
+ },
107
+ dryRun: !!flags.dryRun,
108
+ scopeKey: key,
109
+ attachmentOptions,
110
+ grepOptions: {
111
+ mode: grepMode,
112
+ terms: grepTerms,
113
+ negativeTerms: (0, list_utils_1.uniqueTrimmed)(negativeTerms),
114
+ within: (0, list_utils_1.uniqueTrimmed)(mergedWithin),
115
+ skip: (0, list_utils_1.uniqueTrimmed)(mergedSkip),
116
+ },
117
+ });
118
+ }
119
+ else {
120
+ const scopeEntries = (scope.entry ?? []).map((item) => (0, path_patterns_1.normalizePathOrGlob)(item, root, { role: "entry" }));
121
+ plans.push({
122
+ root,
123
+ command: "scope",
124
+ outputName: scope.name ?? key,
125
+ entry: scopeEntries,
126
+ include: scopeIncludes,
127
+ exclude: (0, list_utils_1.uniqueTrimmed)(scopeExcludes),
128
+ depth,
129
+ maxFiles,
130
+ aliases,
131
+ output: {
132
+ dir: defaultOutput.dir,
133
+ versioned: defaultOutput.versioned,
134
+ format: flags.format ?? defaultOutput.format,
135
+ },
136
+ dryRun: !!flags.dryRun,
137
+ scopeKey: key,
138
+ attachmentOptions,
139
+ });
140
+ }
141
+ }
142
+ return { plans };
143
+ }
@@ -0,0 +1,13 @@
1
+ import type { ExecutionPlan, CommandIntent, ProdexConfigFile, CommandAttachmentOptions } from "../../types";
2
+ export declare function buildTracePlan(params: {
3
+ intent: CommandIntent;
4
+ userConfig: ProdexConfigFile;
5
+ root: string;
6
+ aliases: Record<string, string>;
7
+ depth: number;
8
+ maxFiles: number;
9
+ defaultOutput: ExecutionPlan["output"];
10
+ attachmentOptions: CommandAttachmentOptions | undefined;
11
+ warnings: string[];
12
+ errors: string[];
13
+ }): ExecutionPlan[];
@@ -0,0 +1,77 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildTracePlan = buildTracePlan;
4
+ const default_config_1 = require("../../config/default-config");
5
+ const path_patterns_1 = require("../../filesystem/path-patterns");
6
+ const list_utils_1 = require("./list-utils");
7
+ function buildTracePlan(params) {
8
+ const { intent, userConfig, root, aliases, depth, maxFiles, defaultOutput, attachmentOptions, warnings, errors } = params;
9
+ const flags = intent.flags ?? {};
10
+ // Validation
11
+ if (flags.entry && flags.entry.length > 0) {
12
+ errors.push("`prodex trace --entry` has been removed.\n" +
13
+ "Use `prodex trace --target <target> --depth <number>` to trace from a semantic target.\n" +
14
+ "Use `prodex pack --entry <path-or-glob>` to collect files directly.");
15
+ }
16
+ if (flags.scope !== undefined) {
17
+ errors.push('Command "trace" does not accept "--scope" (or "-s").');
18
+ }
19
+ if (flags.key !== undefined || flags.all !== undefined || flags.list !== undefined) {
20
+ errors.push('Command "trace" does not accept "--key", "--all", or "--list".');
21
+ }
22
+ let finalDepth = depth;
23
+ const configDepth = userConfig.depth !== undefined && userConfig.depth !== null ? userConfig.depth : default_config_1.DEFAULT_PRODEX_CONFIG.depth;
24
+ const hasTarget = flags.target && flags.target.length > 0;
25
+ if (!hasTarget) {
26
+ if (!flags.entry || flags.entry.length === 0) {
27
+ errors.push('Command "trace" requires --target.');
28
+ }
29
+ }
30
+ else {
31
+ // Validate configured default depth
32
+ const configDepthVal = Number(configDepth);
33
+ if (!Number.isInteger(configDepthVal) || configDepthVal < 0) {
34
+ errors.push('--depth must be an integer greater than or equal to 0.');
35
+ }
36
+ if (flags.depth !== undefined && flags.depth !== null) {
37
+ const depthVal = Number(flags.depth);
38
+ if (!Number.isInteger(depthVal) || depthVal < 0) {
39
+ errors.push('--depth must be an integer greater than or equal to 0.');
40
+ }
41
+ else {
42
+ finalDepth = depthVal;
43
+ }
44
+ }
45
+ else {
46
+ if (Number.isInteger(configDepthVal) && configDepthVal >= 0) {
47
+ finalDepth = configDepthVal;
48
+ warnings.push(`No --depth provided. Using configured default depth: ${finalDepth}.\n` +
49
+ `Override with --depth <number> or -d <number>.`);
50
+ }
51
+ }
52
+ }
53
+ if (errors.length)
54
+ return [];
55
+ const mergedExclude = [...(userConfig.exclude ?? []), ...(flags.exclude ?? [])].map((item) => (0, path_patterns_1.normalizePathOrGlob)(item, root, { role: "exclude" }));
56
+ const finalInclude = (flags.include ?? []).map((item) => (0, path_patterns_1.normalizePathOrGlob)(item, root, { role: "include" }));
57
+ const plan = {
58
+ root,
59
+ command: "trace",
60
+ outputName: flags.name,
61
+ entry: [],
62
+ target: (0, list_utils_1.uniqueTrimmed)(flags.target ?? []),
63
+ include: (0, list_utils_1.uniqueTrimmed)(finalInclude),
64
+ exclude: (0, list_utils_1.uniqueTrimmed)(mergedExclude),
65
+ depth: finalDepth,
66
+ maxFiles: flags.maxFiles ?? maxFiles,
67
+ aliases,
68
+ output: {
69
+ dir: defaultOutput.dir,
70
+ versioned: defaultOutput.versioned,
71
+ format: flags.format ?? defaultOutput.format,
72
+ },
73
+ dryRun: !!flags.dryRun,
74
+ attachmentOptions,
75
+ };
76
+ return [plan];
77
+ }
@@ -0,0 +1,5 @@
1
+ import type { ExecutionPlan, SourceCollectionResult } from "../types";
2
+ export interface SourceProvider {
3
+ collect(plan: ExecutionPlan): Promise<SourceCollectionResult>;
4
+ }
5
+ export declare function collectSources(plan: ExecutionPlan): Promise<SourceCollectionResult>;
@@ -0,0 +1,33 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.collectSources = collectSources;
4
+ const dependency_source_provider_1 = require("./dependency-source-provider");
5
+ const git_source_provider_1 = require("./git-source-provider");
6
+ const grep_source_provider_1 = require("./grep-source-provider");
7
+ async function collectSources(plan) {
8
+ switch (plan.command) {
9
+ case "pack":
10
+ case "trace":
11
+ return (0, dependency_source_provider_1.collectDependencySources)(plan);
12
+ case "scope":
13
+ if (plan.grepOptions !== undefined) {
14
+ return (0, grep_source_provider_1.collectGrepSources)(plan);
15
+ }
16
+ return (0, dependency_source_provider_1.collectDependencySources)(plan);
17
+ case "git":
18
+ return (0, git_source_provider_1.collectGitSources)(plan);
19
+ case "grep":
20
+ return (0, grep_source_provider_1.collectGrepSources)(plan);
21
+ default: {
22
+ const exhaustiveCheck = plan.command;
23
+ return {
24
+ files: [],
25
+ entries: [],
26
+ includes: [],
27
+ mode: "include-only",
28
+ warnings: [],
29
+ errors: [`Unsupported command kind for source collection: ${exhaustiveCheck}`],
30
+ };
31
+ }
32
+ }
33
+ }
@@ -0,0 +1,7 @@
1
+ import type { ExecutionPlan } from "../types";
2
+ export interface TargetResolutionResult {
3
+ entries: string[];
4
+ warnings: string[];
5
+ errors: string[];
6
+ }
7
+ export declare function resolveTargets(plan: ExecutionPlan): Promise<TargetResolutionResult>;
@@ -0,0 +1,110 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.resolveTargets = resolveTargets;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
9
+ const exclude_1 = require("../tracing/exclude");
10
+ const entry_discovery_1 = require("../filesystem/entry-discovery");
11
+ const path_patterns_1 = require("../filesystem/path-patterns");
12
+ // runBareNameDiscovery consolidated into discoverBareName from entry-discovery
13
+ function formatAmbiguousTargetError(target, candidates, root) {
14
+ const formattedMatches = candidates
15
+ .map((c) => `- ${path_1.default.relative(root, c).replaceAll("\\", "/")}`)
16
+ .join("\n");
17
+ const exampleCandidate = candidates[1] || candidates[0];
18
+ const relativeCandidate = path_1.default.relative(root, exampleCandidate).replaceAll("\\", "/");
19
+ const ext = path_1.default.extname(relativeCandidate);
20
+ const suggestion = ext ? relativeCandidate.slice(0, -ext.length) : relativeCandidate;
21
+ const targetStem = path_1.default.basename(target, path_1.default.extname(target));
22
+ const uniqueExts = [...new Set(candidates.map((c) => path_1.default.extname(c).toLowerCase()))];
23
+ const extensionsDiffer = uniqueExts.length > 1;
24
+ const packExtension = extensionsDiffer ? ".*" : (uniqueExts[0] || ".ts");
25
+ return `Ambiguous target "${target}". Matches:\n` +
26
+ `${formattedMatches}\n\n` +
27
+ `Use a more specific target, such as:\n` +
28
+ ` prodex trace --target ${suggestion} --depth 2\n\n` +
29
+ `If you intended to collect all matching files directly, use a glob with pack:\n` +
30
+ ` prodex pack --entry "src/**/${targetStem}${packExtension}"`;
31
+ }
32
+ async function resolveTargets(plan) {
33
+ const resolved = [];
34
+ const errors = [];
35
+ const warnings = [];
36
+ const root = plan.root;
37
+ const excludes = plan.exclude;
38
+ const targets = plan.target ?? [];
39
+ for (const target of targets) {
40
+ if ((0, path_patterns_1.isGlobPattern)(target)) {
41
+ errors.push(`Command "trace" does not accept glob targets.\n` +
42
+ `Use \`prodex pack --entry <glob>\` to collect files directly.`);
43
+ continue;
44
+ }
45
+ // 1. Exact path match
46
+ const absPath = path_1.default.resolve(root, target);
47
+ let isFile = false;
48
+ try {
49
+ isFile = fs_1.default.statSync(absPath).isFile();
50
+ }
51
+ catch { }
52
+ if (isFile) {
53
+ if (!(0, exclude_1.isExcluded)(absPath, excludes, root)) {
54
+ resolved.push(absPath);
55
+ }
56
+ continue;
57
+ }
58
+ // 2. Extensionless path expansion
59
+ const hasExt = path_1.default.extname(target) !== "";
60
+ if (!hasExt) {
61
+ const step2Matches = (0, entry_discovery_1.expandPathLike)(target, root);
62
+ const step2NonExcluded = step2Matches.filter((file) => !(0, exclude_1.isExcluded)(file, excludes, root));
63
+ if (step2NonExcluded.length > 0) {
64
+ if (step2NonExcluded.length === 1) {
65
+ resolved.push(step2NonExcluded[0]);
66
+ }
67
+ else {
68
+ errors.push(formatAmbiguousTargetError(target, step2NonExcluded, root));
69
+ }
70
+ continue;
71
+ }
72
+ }
73
+ // 3. Bare-name discovery
74
+ const isPathLike = target.includes("/") || target.includes("\\");
75
+ if (!isPathLike) {
76
+ const step3Matches = await (0, entry_discovery_1.discoverBareName)(target, root, true);
77
+ const step3NonExcluded = step3Matches.filter((file) => !(0, exclude_1.isExcluded)(file, excludes, root));
78
+ if (step3NonExcluded.length > 0) {
79
+ if (step3NonExcluded.length === 1) {
80
+ resolved.push(step3NonExcluded[0]);
81
+ }
82
+ else {
83
+ errors.push(formatAmbiguousTargetError(target, step3NonExcluded, root));
84
+ }
85
+ continue;
86
+ }
87
+ }
88
+ // 4. Case-insensitive bare-name discovery
89
+ if (!isPathLike) {
90
+ const step4Matches = await (0, entry_discovery_1.discoverBareName)(target, root, false);
91
+ const step4NonExcluded = step4Matches.filter((file) => !(0, exclude_1.isExcluded)(file, excludes, root));
92
+ if (step4NonExcluded.length > 0) {
93
+ if (step4NonExcluded.length === 1) {
94
+ resolved.push(step4NonExcluded[0]);
95
+ }
96
+ else {
97
+ errors.push(formatAmbiguousTargetError(target, step4NonExcluded, root));
98
+ }
99
+ continue;
100
+ }
101
+ }
102
+ // Fail clearly if no matches found
103
+ errors.push(`Target "${target}" did not match any files.`);
104
+ }
105
+ return {
106
+ entries: [...new Set(resolved)],
107
+ errors,
108
+ warnings,
109
+ };
110
+ }
@@ -9,7 +9,7 @@ function parseCliInput(argv = process.argv) {
9
9
  const errors = [];
10
10
  const flags = {};
11
11
  if (!tokens.length) {
12
- errors.push("Missing command. Use `prodex run`, `prodex init`, `prodex profiles`, or `prodex migrate`.");
12
+ errors.push("Missing command. Use `prodex pack`, `prodex trace`, `prodex scope`, `prodex grep`, `prodex git`, or `prodex migrate`.");
13
13
  return { warnings, errors };
14
14
  }
15
15
  if (tokens.includes("--version") || tokens.includes("-v")) {
@@ -20,21 +20,25 @@ function parseCliInput(argv = process.argv) {
20
20
  }
21
21
  const commandName = tokens[0];
22
22
  if (!isCommand(commandName)) {
23
- errors.push(`Unknown command "${commandName}". Use run, init, profiles, or migrate.`);
23
+ errors.push(`Unknown command "${commandName}". Use pack, trace, scope, grep, git, or migrate.`);
24
24
  return { warnings, errors };
25
25
  }
26
+ const isGrep = commandName === "grep";
27
+ const flagsByLong = isGrep ? flag_specs_1.GREP_FLAGS_BY_LONG : flag_specs_1.FLAGS_BY_LONG;
28
+ const flagsByShort = isGrep ? flag_specs_1.GREP_FLAGS_BY_SHORT : flag_specs_1.FLAGS_BY_SHORT;
29
+ const flagAliases = isGrep ? flag_specs_1.GREP_FLAG_ALIASES : flag_specs_1.FLAG_ALIASES;
26
30
  let rootArg;
27
31
  for (let i = 1; i < tokens.length; i++) {
28
32
  const token = tokens[i];
29
33
  if (!token)
30
34
  continue;
31
35
  if (token.startsWith("--")) {
32
- const consumed = readLongFlag(tokens, i, flags, errors);
36
+ const consumed = readLongFlag(tokens, i, flags, errors, flagAliases, flagsByLong);
33
37
  i += consumed;
34
38
  continue;
35
39
  }
36
40
  if (token.startsWith("-") && token !== "-") {
37
- const consumed = readShortFlag(tokens, i, flags, errors);
41
+ const consumed = readShortFlag(tokens, i, flags, errors, flagsByShort);
38
42
  i += consumed;
39
43
  continue;
40
44
  }
@@ -46,14 +50,57 @@ function parseCliInput(argv = process.argv) {
46
50
  }
47
51
  if (flags.help)
48
52
  return { command: { kind: "help", topic: commandName }, warnings, errors };
49
- if (commandName === "init")
53
+ const validationErrors = validateCliInput(commandName, flags);
54
+ errors.push(...validationErrors);
55
+ if (errors.length) {
56
+ return { warnings, errors };
57
+ }
58
+ if (commandName === "init") {
50
59
  return { command: { kind: "init", rootArg }, warnings, errors };
51
- if (commandName === "profiles")
52
- return { command: { kind: "profiles", rootArg }, warnings, errors };
60
+ }
53
61
  if (commandName === "migrate") {
54
62
  return { command: { kind: "migrate", rootArg, write: !!flags.write, check: !!flags.check }, warnings, errors };
55
63
  }
56
- return { command: { kind: "run", rootArg, flags }, warnings, errors };
64
+ if (commandName === "pack") {
65
+ return { command: { kind: "pack", rootArg, flags }, warnings, errors };
66
+ }
67
+ if (commandName === "trace") {
68
+ return { command: { kind: "trace", rootArg, flags }, warnings, errors };
69
+ }
70
+ if (commandName === "scope") {
71
+ return { command: { kind: "scope", rootArg, flags }, warnings, errors };
72
+ }
73
+ if (commandName === "git") {
74
+ return { command: { kind: "git", rootArg, flags }, warnings, errors };
75
+ }
76
+ if (commandName === "grep") {
77
+ return { command: { kind: "grep", rootArg, flags }, warnings, errors };
78
+ }
79
+ return { warnings, errors };
80
+ }
81
+ function validateCliInput(commandName, flags) {
82
+ const errors = [];
83
+ if (commandName === "run") {
84
+ errors.push("`prodex run` has been replaced.\nUse `prodex pack`, `prodex trace`, or `prodex scope`.");
85
+ }
86
+ if (commandName === "profiles") {
87
+ errors.push("`prodex profiles` has been replaced.\nUse `prodex scope --list`.");
88
+ }
89
+ if (flags.profile !== undefined) {
90
+ errors.push("`--profile` has been replaced.\nUse `prodex pack --scope <key>` to merge scopes into one pack, or `prodex scope -k <key>` to run configured scopes separately.");
91
+ }
92
+ if (flags.allProfiles !== undefined) {
93
+ errors.push("`--all-profiles` has been replaced.\nUse `--all` with `prodex scope`.");
94
+ }
95
+ if (flags.maxDepth !== undefined) {
96
+ errors.push("`--max-depth` has been replaced.\nUse `--depth`.");
97
+ }
98
+ if (commandName === "init" || commandName === "migrate") {
99
+ if (flags.cmd !== undefined || flags.cmdTimeout !== undefined || flags.failOnCmdError !== undefined) {
100
+ errors.push(`Command "${commandName}" does not accept command attachment options.`);
101
+ }
102
+ }
103
+ return errors;
57
104
  }
58
105
  function stripExecutable(argv) {
59
106
  const [first, second, ...rest] = argv;
@@ -73,14 +120,14 @@ function basename(value) {
73
120
  function isCommand(token) {
74
121
  return flag_specs_1.COMMANDS.includes(token);
75
122
  }
76
- function readLongFlag(tokens, index, flags, errors) {
123
+ function readLongFlag(tokens, index, flags, errors, flagAliases, flagsByLong) {
77
124
  const token = tokens[index];
78
125
  const raw = token.slice(2);
79
126
  const equalsAt = raw.indexOf("=");
80
127
  const rawName = equalsAt === -1 ? raw : raw.slice(0, equalsAt);
81
- const name = flag_specs_1.FLAG_ALIASES[rawName] ?? rawName;
128
+ const name = flagAliases[rawName] ?? rawName;
82
129
  const inlineValue = equalsAt === -1 ? undefined : raw.slice(equalsAt + 1);
83
- const spec = flag_specs_1.FLAGS_BY_LONG.get(name);
130
+ const spec = flagsByLong.get(name);
84
131
  if (!spec) {
85
132
  errors.push(`Unknown flag "--${rawName}".`);
86
133
  return 0;
@@ -90,19 +137,19 @@ function readLongFlag(tokens, index, flags, errors) {
90
137
  return 0;
91
138
  }
92
139
  const value = inlineValue ?? tokens[index + 1];
93
- if (value === undefined || value.startsWith("-")) {
140
+ if (value === undefined || (value.startsWith("-") && !/^-?\d+(\.\d+)?$/.test(value))) {
94
141
  errors.push(`Flag "--${rawName}" expects a value.`);
95
142
  return 0;
96
143
  }
97
144
  assignFlag(flags, spec, value, errors);
98
145
  return inlineValue === undefined ? 1 : 0;
99
146
  }
100
- function readShortFlag(tokens, index, flags, errors) {
147
+ function readShortFlag(tokens, index, flags, errors, flagsByShort) {
101
148
  const token = tokens[index];
102
149
  const cluster = token.slice(1);
103
150
  if (cluster.length > 1) {
104
151
  for (const ch of cluster) {
105
- const spec = flag_specs_1.FLAGS_BY_SHORT.get(ch);
152
+ const spec = flagsByShort.get(ch);
106
153
  if (!spec) {
107
154
  errors.push(`Unknown flag "-${ch}".`);
108
155
  continue;
@@ -115,7 +162,7 @@ function readShortFlag(tokens, index, flags, errors) {
115
162
  }
116
163
  return 0;
117
164
  }
118
- const spec = flag_specs_1.FLAGS_BY_SHORT.get(cluster);
165
+ const spec = flagsByShort.get(cluster);
119
166
  if (!spec) {
120
167
  errors.push(`Unknown flag "-${cluster}".`);
121
168
  return 0;
@@ -125,7 +172,7 @@ function readShortFlag(tokens, index, flags, errors) {
125
172
  return 0;
126
173
  }
127
174
  const value = tokens[index + 1];
128
- if (value === undefined || value.startsWith("-")) {
175
+ if (value === undefined || (value.startsWith("-") && !/^-?\d+(\.\d+)?$/.test(value))) {
129
176
  errors.push(`Flag "-${cluster}" expects a value.`);
130
177
  return 0;
131
178
  }
@@ -143,9 +190,13 @@ function assignFlag(flags, spec, value, errors) {
143
190
  }
144
191
  if (spec.type === "list") {
145
192
  const values = (0, string_list_1.splitStringList)(value);
146
- const target = spec.long === "profile" ? "profiles" : spec.long;
147
- const current = (flags[target] ?? []);
148
- flags[target] = [...current, ...values];
193
+ const current = (flags[spec.long] ?? []);
194
+ flags[spec.long] = [...current, ...values];
195
+ return;
196
+ }
197
+ if (spec.type === "raw-list") {
198
+ const current = (flags[spec.long] ?? []);
199
+ flags[spec.long] = [...current, value];
149
200
  return;
150
201
  }
151
202
  if (spec.long === "format" && !["md", "txt"].includes(value)) {