patram 0.7.0 → 0.9.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 (140) hide show
  1. package/bin/patram.js +2 -2
  2. package/lib/{parse-cli-color-options.js → cli/color-options.js} +2 -2
  3. package/lib/cli/command-helpers.js +35 -0
  4. package/lib/cli/commands/check.js +73 -0
  5. package/lib/cli/commands/fields.js +57 -0
  6. package/lib/cli/commands/queries.js +41 -0
  7. package/lib/cli/commands/query.js +239 -0
  8. package/lib/cli/commands/refs.js +72 -0
  9. package/lib/cli/commands/show.js +58 -0
  10. package/lib/{cli-help-metadata.js → cli/help-metadata.js} +54 -15
  11. package/lib/cli/main.js +76 -0
  12. package/lib/{parse-cli-arguments-helpers.js → cli/parse-arguments-helpers.js} +18 -11
  13. package/lib/{parse-cli-arguments.js → cli/parse-arguments.js} +12 -12
  14. package/lib/{parse-cli-query-pagination.js → cli/query-pagination.js} +2 -2
  15. package/lib/{render-cli-help.js → cli/render-help.js} +4 -4
  16. package/lib/{resolve-output-mode.js → cli/resolve-output-mode.js} +2 -2
  17. package/lib/cli/test-helpers.js +30 -0
  18. package/lib/config/defaults.d.ts +10 -0
  19. package/lib/config/defaults.js +80 -0
  20. package/lib/config/load-patram-config.d.ts +76 -0
  21. package/lib/config/load-patram-config.js +315 -0
  22. package/lib/config/load-patram-config.types.d.ts +45 -0
  23. package/lib/{patram-config.d.ts → config/patram-config.d.ts} +31 -31
  24. package/lib/{patram-config.js → config/patram-config.js} +3 -3
  25. package/lib/{patram-config.types.d.ts → config/patram-config.types.d.ts} +1 -1
  26. package/lib/{resolve-patram-graph-config.d.ts → config/resolve-patram-graph-config.d.ts} +2 -2
  27. package/lib/{resolve-patram-graph-config.js → config/resolve-patram-graph-config.js} +3 -3
  28. package/lib/{load-patram-config.d.ts → config/schema.d.ts} +147 -191
  29. package/lib/config/schema.js +324 -0
  30. package/lib/{source-file-defaults.d.ts → config/source-file-defaults.d.ts} +0 -1
  31. package/lib/{source-file-defaults.js → config/source-file-defaults.js} +1 -1
  32. package/lib/config/validation.d.ts +27 -0
  33. package/lib/config/validation.js +615 -0
  34. package/lib/directive-validation-test-helpers.js +1 -1
  35. package/lib/{build-graph-identity.d.ts → graph/build-graph-identity.d.ts} +2 -2
  36. package/lib/{build-graph-identity.js → graph/build-graph-identity.js} +1 -1
  37. package/lib/{build-graph.d.ts → graph/build-graph.d.ts} +3 -3
  38. package/lib/{build-graph.js → graph/build-graph.js} +17 -13
  39. package/lib/{build-graph.types.d.ts → graph/build-graph.types.d.ts} +1 -1
  40. package/lib/graph/check-directive-metadata.d.ts +23 -0
  41. package/lib/{check-directive-metadata.js → graph/check-directive-metadata.js} +7 -7
  42. package/lib/graph/check-directive-path-target.d.ts +32 -0
  43. package/lib/{check-directive-path-target.js → graph/check-directive-path-target.js} +4 -4
  44. package/lib/graph/check-directive-value.d.ts +19 -0
  45. package/lib/{check-directive-value.js → graph/check-directive-value.js} +3 -3
  46. package/lib/graph/check-graph.d.ts +29 -0
  47. package/lib/{check-graph.js → graph/check-graph.js} +6 -6
  48. package/lib/graph/directive-diagnostics.d.ts +20 -0
  49. package/lib/{directive-diagnostics.js → graph/directive-diagnostics.js} +2 -2
  50. package/lib/graph/directive-type-rules.d.ts +18 -0
  51. package/lib/{directive-type-rules.js → graph/directive-type-rules.js} +3 -3
  52. package/lib/{document-node-identity.d.ts → graph/document-node-identity.d.ts} +2 -2
  53. package/lib/{document-node-identity.js → graph/document-node-identity.js} +2 -2
  54. package/lib/graph/inspect-reverse-references.d.ts +22 -0
  55. package/lib/graph/inspect-reverse-references.js +184 -0
  56. package/lib/{load-project-graph.d.ts → graph/load-project-graph.d.ts} +10 -10
  57. package/lib/{load-project-graph.js → graph/load-project-graph.js} +12 -12
  58. package/lib/{parse-where-clause.types.d.ts → graph/parse-where-clause.types.d.ts} +1 -1
  59. package/lib/{query-graph.d.ts → graph/query/execute.d.ts} +11 -11
  60. package/lib/{query-graph.js → graph/query/execute.js} +12 -12
  61. package/lib/{query-inspection.d.ts → graph/query/inspect.d.ts} +10 -8
  62. package/lib/{query-inspection.js → graph/query/inspect.js} +16 -17
  63. package/lib/{parse-where-clause.d.ts → graph/query/parse.d.ts} +6 -6
  64. package/lib/{parse-where-clause.js → graph/query/parse.js} +2 -2
  65. package/lib/graph/query/resolve.d.ts +30 -0
  66. package/lib/{resolve-where-clause.js → graph/query/resolve.js} +1 -1
  67. package/lib/graph/reverse-reference-test-helpers.d.ts +55 -0
  68. package/lib/graph/reverse-reference-test-helpers.js +76 -0
  69. package/lib/{command-output.js → output/command-output.js} +6 -5
  70. package/lib/{derived-summary.js → output/derived-summary.js} +7 -7
  71. package/lib/output/layout-incoming-references.js +105 -0
  72. package/lib/output/layout-incoming-summary-lines.js +16 -0
  73. package/lib/{layout-stored-queries.js → output/layout-stored-queries.js} +9 -9
  74. package/lib/{list-queries.js → output/list-queries.js} +1 -1
  75. package/lib/{render-check-output.js → output/render-check-output.js} +1 -1
  76. package/lib/{render-field-discovery.js → output/render-field-discovery.js} +3 -3
  77. package/lib/output/render-output-view.js +56 -0
  78. package/lib/{render-json-output.js → output/renderers/json.js} +92 -63
  79. package/lib/{render-plain-output.js → output/renderers/plain.js} +62 -7
  80. package/lib/{render-rich-output.js → output/renderers/rich.js} +69 -8
  81. package/lib/{resolve-check-target.js → output/resolve-check-target.js} +1 -1
  82. package/lib/{render-rich-source.js → output/rich-source/render.js} +6 -6
  83. package/lib/{show-document.js → output/show-document.js} +54 -16
  84. package/lib/{render-output-view.js → output/view-model/index.js} +56 -47
  85. package/lib/{write-paged-output.js → output/write-paged-output.js} +9 -5
  86. package/lib/{claim-helpers.d.ts → parse/claim-helpers.d.ts} +2 -2
  87. package/lib/{parse-jsdoc-claims.d.ts → parse/jsdoc/parse-jsdoc-claims.d.ts} +2 -2
  88. package/lib/{parse-jsdoc-claims.js → parse/jsdoc/parse-jsdoc-claims.js} +9 -9
  89. package/lib/{parse-jsdoc-prose.d.ts → parse/jsdoc/parse-jsdoc-prose.d.ts} +1 -1
  90. package/lib/{parse-jsdoc-prose.js → parse/jsdoc/parse-jsdoc-prose.js} +1 -1
  91. package/lib/{parse-markdown-claims.d.ts → parse/markdown/parse-markdown-claims.d.ts} +3 -3
  92. package/lib/{parse-markdown-claims.js → parse/markdown/parse-markdown-claims.js} +8 -8
  93. package/lib/{parse-markdown-directives.d.ts → parse/markdown/parse-markdown-directives.d.ts} +2 -2
  94. package/lib/{parse-markdown-directives.js → parse/markdown/parse-markdown-directives.js} +3 -3
  95. package/lib/{parse-claims.d.ts → parse/parse-claims.d.ts} +4 -13
  96. package/lib/{parse-claims.js → parse/parse-claims.js} +18 -26
  97. package/lib/{parse-claims.types.d.ts → parse/parse-claims.types.d.ts} +1 -1
  98. package/lib/{tagged-fenced-block-error.d.ts → parse/tagged-fenced/tagged-fenced-block-error.d.ts} +2 -2
  99. package/lib/{tagged-fenced-block-parser.d.ts → parse/tagged-fenced/tagged-fenced-block-parser.d.ts} +3 -3
  100. package/lib/{tagged-fenced-blocks.d.ts → parse/tagged-fenced/tagged-fenced-blocks.d.ts} +7 -7
  101. package/lib/{tagged-fenced-blocks.js → parse/tagged-fenced/tagged-fenced-blocks.js} +3 -3
  102. package/lib/{parse-yaml-claims.d.ts → parse/yaml/parse-yaml-claims.d.ts} +4 -4
  103. package/lib/{parse-yaml-claims.js → parse/yaml/parse-yaml-claims.js} +22 -13
  104. package/lib/patram.d.ts +29 -28
  105. package/lib/patram.js +5 -6
  106. package/lib/{discover-fields.js → scan/discover-fields.js} +9 -8
  107. package/lib/scan/list-repo-files.d.ts +16 -0
  108. package/lib/{list-source-files.js → scan/list-repo-files.js} +2 -35
  109. package/lib/{list-source-files.d.ts → scan/list-source-files.d.ts} +4 -11
  110. package/lib/scan/list-source-files.js +45 -0
  111. package/package.json +8 -7
  112. package/lib/build-graph.types.ts +0 -27
  113. package/lib/discover-fields.types.ts +0 -52
  114. package/lib/load-patram-config.js +0 -1215
  115. package/lib/load-patram-config.types.d.ts +0 -45
  116. package/lib/load-patram-config.types.ts +0 -56
  117. package/lib/output-view.types.d.ts +0 -80
  118. package/lib/output-view.types.ts +0 -96
  119. package/lib/overlay-graph.d.ts +0 -43
  120. package/lib/overlay-graph.js +0 -191
  121. package/lib/parse-claims.types.ts +0 -41
  122. package/lib/parse-cli-arguments.types.ts +0 -69
  123. package/lib/parse-where-clause.types.ts +0 -87
  124. package/lib/patram-cli.js +0 -528
  125. package/lib/patram-config.types.ts +0 -22
  126. package/lib/tagged-fenced-blocks.types.ts +0 -38
  127. /package/lib/{format-derived-summary-row.js → output/format-derived-summary-row.js} +0 -0
  128. /package/lib/{format-node-header.js → output/format-node-header.js} +0 -0
  129. /package/lib/{format-output-item-block.js → output/format-output-item-block.js} +0 -0
  130. /package/lib/{format-output-metadata.js → output/format-output-metadata.js} +0 -0
  131. /package/lib/{claim-helpers.js → parse/claim-helpers.js} +0 -0
  132. /package/lib/{parse-jsdoc-blocks.d.ts → parse/jsdoc/parse-jsdoc-blocks.d.ts} +0 -0
  133. /package/lib/{parse-jsdoc-blocks.js → parse/jsdoc/parse-jsdoc-blocks.js} +0 -0
  134. /package/lib/{tagged-fenced-block-error.js → parse/tagged-fenced/tagged-fenced-block-error.js} +0 -0
  135. /package/lib/{tagged-fenced-block-markdown.d.ts → parse/tagged-fenced/tagged-fenced-block-markdown.d.ts} +0 -0
  136. /package/lib/{tagged-fenced-block-markdown.js → parse/tagged-fenced/tagged-fenced-block-markdown.js} +0 -0
  137. /package/lib/{tagged-fenced-block-metadata.d.ts → parse/tagged-fenced/tagged-fenced-block-metadata.d.ts} +0 -0
  138. /package/lib/{tagged-fenced-block-metadata.js → parse/tagged-fenced/tagged-fenced-block-metadata.js} +0 -0
  139. /package/lib/{tagged-fenced-block-parser.js → parse/tagged-fenced/tagged-fenced-block-parser.js} +0 -0
  140. /package/lib/{tagged-fenced-blocks.types.d.ts → parse/tagged-fenced/tagged-fenced-blocks.types.d.ts} +0 -0
@@ -3,7 +3,7 @@
3
3
  * @import {
4
4
  * CliCommandName,
5
5
  * CliHelpTopicName,
6
- * } from './parse-cli-arguments.types.ts';
6
+ * } from './arguments.types.ts';
7
7
  */
8
8
 
9
9
  /**
@@ -45,15 +45,16 @@
45
45
  * }} CliHelpTopicDefinition
46
46
  */
47
47
 
48
- export const COMMAND_NAMES = /** @type {const} */ ([
48
+ const COMMAND_NAMES = /** @type {const} */ ([
49
49
  'check',
50
50
  'fields',
51
51
  'query',
52
52
  'queries',
53
+ 'refs',
53
54
  'show',
54
55
  ]);
55
56
 
56
- export const HELP_TOPIC_NAMES = /** @type {const} */ (['query-language']);
57
+ const HELP_TOPIC_NAMES = /** @type {const} */ (['query-language']);
57
58
 
58
59
  export const GLOBAL_OPTION_NAMES = new Set([
59
60
  'help',
@@ -146,12 +147,12 @@ const COMMAND_DEFINITIONS = {
146
147
  ]),
147
148
  examples: [
148
149
  'patram query active-plans',
149
- 'patram query --where "tracked_in=doc:docs/plans/v0/worktracking-agent-guidance.md"',
150
- 'patram query --where "status not in [done, dropped, superseded]"',
151
- 'patram query --where "$class=plan and none(in:tracked_in, $class=decision)"',
152
- 'patram query --where "count(in:decided_by, $class=task) = 0"',
150
+ "patram query --where 'tracked_in=doc:docs/plans/v0/worktracking-agent-guidance.md'",
151
+ "patram query --where 'status not in [done, dropped, superseded]'",
152
+ "patram query --where '$class=plan and none(in:tracked_in, $class=decision)'",
153
+ "patram query --where 'count(in:decided_by, $class=task) = 0'",
153
154
  'patram query ready-tasks --explain',
154
- 'patram query --where "$class=decision and status=accepted and count(in:decided_by, $class=task) = 0" --lint',
155
+ "patram query --where '$class=decision and status=accepted and count(in:decided_by, $class=task) = 0' --lint",
155
156
  'patram query active-plans --limit 10 --offset 20',
156
157
  ],
157
158
  extra_positionals_message:
@@ -161,12 +162,12 @@ const COMMAND_DEFINITIONS = {
161
162
  min_positionals: 0,
162
163
  missing_argument_examples: [
163
164
  'patram query active-plans',
164
- 'patram query --where "tracked_in=doc:docs/plans/v0/worktracking-agent-guidance.md"',
165
+ "patram query --where 'tracked_in=doc:docs/plans/v0/worktracking-agent-guidance.md'",
165
166
  ],
166
- missing_argument_label: '<name> or --where "<clause>"',
167
+ missing_argument_label: "<name> or --where '<clause>'",
167
168
  missing_usage_lines: [
168
169
  'patram query <name> [options]',
169
- 'patram query --where "<clause>" [options]',
170
+ "patram query --where '<clause>' [options]",
170
171
  ],
171
172
  option_column_width: 19,
172
173
  options: [
@@ -214,7 +215,7 @@ const COMMAND_DEFINITIONS = {
214
215
  ],
215
216
  usage_lines: [
216
217
  'patram query <name> [options]',
217
- 'patram query --where "<clause>" [options]',
218
+ "patram query --where '<clause>' [options]",
218
219
  ],
219
220
  },
220
221
  queries: {
@@ -243,16 +244,54 @@ const COMMAND_DEFINITIONS = {
243
244
  summary: 'List the stored queries defined in the project configuration.',
244
245
  usage_lines: ['patram queries [options]'],
245
246
  },
247
+ refs: {
248
+ allowed_option_names: new Set(['where']),
249
+ examples: [
250
+ 'patram refs docs/decisions/query-language.md',
251
+ "patram refs docs/decisions/query-language.md --where '$class=document'",
252
+ 'patram refs docs/decisions/query-language.md --json',
253
+ ],
254
+ extra_positionals_message: 'Refs accepts exactly one file path.',
255
+ help_topics: ['query-language'],
256
+ max_positionals: 1,
257
+ min_positionals: 1,
258
+ missing_argument_examples: [
259
+ 'patram refs docs/decisions/query-language.md',
260
+ "patram refs docs/patram.md --where '$class=document'",
261
+ ],
262
+ missing_argument_label: '<file>',
263
+ missing_usage_lines: ['patram refs <file>'],
264
+ option_column_width: 19,
265
+ options: [
266
+ {
267
+ description: 'Filter incoming source nodes with a where clause',
268
+ label: '--where <clause>',
269
+ },
270
+ {
271
+ description: 'Print plain text output',
272
+ label: '--plain',
273
+ },
274
+ {
275
+ description: 'Print JSON output',
276
+ label: '--json',
277
+ },
278
+ ],
279
+ related: ['show', 'query'],
280
+ root_summary: 'Inspect incoming graph references for one file',
281
+ summary:
282
+ 'Inspect incoming graph references for one file, grouped by relation.',
283
+ usage_lines: ['patram refs <file> [options]'],
284
+ },
246
285
  show: {
247
286
  allowed_option_names: new Set(),
248
- examples: ['patram show docs/patram.md', 'patram show lib/patram-cli.js'],
287
+ examples: ['patram show docs/patram.md', 'patram show lib/cli/main.js'],
249
288
  extra_positionals_message: 'Show accepts exactly one file path.',
250
289
  help_topics: [],
251
290
  max_positionals: 1,
252
291
  min_positionals: 1,
253
292
  missing_argument_examples: [
254
293
  'patram show docs/patram.md',
255
- 'patram show lib/patram-cli.js',
294
+ 'patram show lib/cli/main.js',
256
295
  ],
257
296
  missing_argument_label: '<file>',
258
297
  missing_usage_lines: ['patram show <file>'],
@@ -544,7 +583,7 @@ function scoreCandidate(input_text, candidate) {
544
583
  function calculateDamerauLevenshteinDistance(left_text, right_text) {
545
584
  /** @type {number[][]} */
546
585
  const matrix = Array.from({ length: left_text.length + 1 }, () =>
547
- Array(right_text.length + 1).fill(0),
586
+ Array.from({ length: right_text.length + 1 }, () => 0),
548
587
  );
549
588
 
550
589
  for (let left_index = 0; left_index <= left_text.length; left_index += 1) {
@@ -0,0 +1,76 @@
1
+ /**
2
+ * @import { ParsedCliCommandRequest } from './arguments.types.ts';
3
+ */
4
+ import { renderCliParseError, renderHelpRequest } from './render-help.js';
5
+ import { parseCliArguments } from './parse-arguments.js';
6
+ import { runCheckCommand } from './commands/check.js';
7
+ import { runFieldsCommand } from './commands/fields.js';
8
+ import { runQueryCommand } from './commands/query.js';
9
+ import { runQueriesCommand } from './commands/queries.js';
10
+ import { runRefsCommand } from './commands/refs.js';
11
+ import { runShowCommand } from './commands/show.js';
12
+
13
+ /**
14
+ * Patram command execution flow.
15
+ *
16
+ * Loads repo state and routes `check`, `fields`, `query`, `queries`, and
17
+ * `show` through the shared output pipeline.
18
+ *
19
+ * Kind: cli
20
+ * Status: active
21
+ * Implements Command: ../../docs/reference/commands/check.md
22
+ * Implements Command: ../../docs/reference/commands/query.md
23
+ * Implements Command: ../../docs/reference/commands/queries.md
24
+ * Implements Command: ../../docs/reference/commands/refs.md
25
+ * Implements Command: ../../docs/reference/commands/show.md
26
+ * Tracked in: ../../docs/plans/v0/source-anchor-dogfooding.md
27
+ * Decided by: ../../docs/decisions/cli-output-architecture.md
28
+ * Decided by: ../../docs/decisions/cli-argument-parser.md
29
+ * @patram
30
+ * @see {@link ./parse-arguments.js}
31
+ * @see {@link ./commands/query.js}
32
+ */
33
+
34
+ /**
35
+ * Run the Patram CLI.
36
+ *
37
+ * @param {string[]} cli_arguments
38
+ * @param {{ stderr: { write(chunk: string): boolean }, stdout: { isTTY?: boolean, write(chunk: string): boolean }, write_paged_output?: (output_text: string) => Promise<void> }} io_context
39
+ * @returns {Promise<number>}
40
+ */
41
+ export async function main(cli_arguments, io_context) {
42
+ const parsed_arguments = parseCliArguments(cli_arguments);
43
+
44
+ if (!parsed_arguments.success) {
45
+ io_context.stderr.write(renderCliParseError(parsed_arguments.error));
46
+
47
+ return 1;
48
+ }
49
+
50
+ if (parsed_arguments.value.kind === 'help') {
51
+ io_context.stdout.write(renderHelpRequest(parsed_arguments.value));
52
+
53
+ return 0;
54
+ }
55
+
56
+ const parsed_command = /** @type {ParsedCliCommandRequest} */ (
57
+ parsed_arguments.value
58
+ );
59
+ const commandHandler = COMMAND_HANDLERS[parsed_command.command_name];
60
+
61
+ if (commandHandler) {
62
+ return commandHandler(parsed_command, io_context);
63
+ }
64
+
65
+ io_context.stderr.write('Unknown command.\n');
66
+
67
+ return 1;
68
+ }
69
+ const COMMAND_HANDLERS = {
70
+ check: runCheckCommand,
71
+ fields: runFieldsCommand,
72
+ queries: runQueriesCommand,
73
+ query: runQueryCommand,
74
+ refs: runRefsCommand,
75
+ show: runShowCommand,
76
+ };
@@ -1,9 +1,9 @@
1
1
  /* eslint-disable max-lines */
2
2
  /**
3
- * @typedef {import('./parse-cli-arguments.types.ts').CliCommandName} CliCommandName
4
- * @typedef {import('./parse-cli-arguments.types.ts').CliOutputMode} CliOutputMode
5
- * @typedef {import('./parse-cli-arguments.types.ts').CliParseError} CliParseError
6
- * @typedef {import('./parse-cli-arguments.types.ts').ParsedCliHelpRequest} ParsedCliHelpRequest
3
+ * @typedef {import('./arguments.types.ts').CliCommandName} CliCommandName
4
+ * @typedef {import('./arguments.types.ts').CliOutputMode} CliOutputMode
5
+ * @typedef {import('./arguments.types.ts').CliParseError} CliParseError
6
+ * @typedef {import('./arguments.types.ts').ParsedCliHelpRequest} ParsedCliHelpRequest
7
7
  * @typedef {{ kind: string, name?: string, rawName?: string, value?: string | boolean }} CliOptionToken
8
8
  * @typedef {{ color?: string, explain?: boolean, help?: boolean, json?: boolean, limit?: string, lint?: boolean, 'no-color'?: boolean, offset?: string, plain?: boolean, where?: string }} CliOptionValues
9
9
  * @typedef {{ option_tokens: CliOptionToken[], positionals: string[], values: CliOptionValues }} ParsedCommandLine
@@ -17,9 +17,9 @@ import {
17
17
  GLOBAL_OPTION_NAMES,
18
18
  isCommandName,
19
19
  isHelpTopicName,
20
- } from './cli-help-metadata.js';
21
- import { findInvalidColorMode } from './parse-cli-color-options.js';
22
- import { findInvalidQueryPagination } from './parse-cli-query-pagination.js';
20
+ } from './help-metadata.js';
21
+ import { findInvalidColorMode } from './color-options.js';
22
+ import { findInvalidQueryPagination } from './query-pagination.js';
23
23
 
24
24
  export const CLI_OPTIONS = /** @type {const} */ ({
25
25
  color: { type: 'string' },
@@ -160,6 +160,10 @@ export function buildCommandArguments(
160
160
  return ['--where', parsed_values.where];
161
161
  }
162
162
 
163
+ if (command_name === 'refs' && parsed_values.where !== undefined) {
164
+ return [command_positionals[0], '--where', parsed_values.where];
165
+ }
166
+
163
167
  return command_positionals;
164
168
  }
165
169
 
@@ -305,7 +309,7 @@ function findMissingOptionValue(option_tokens) {
305
309
  for (const token of option_tokens) {
306
310
  if (token.name === 'where' && typeof token.value !== 'string') {
307
311
  return {
308
- argument_label: '<name> or --where "<clause>"',
312
+ argument_label: "<name> or --where '<clause>'",
309
313
  code: 'missing_required_argument',
310
314
  command_name: 'query',
311
315
  };
@@ -401,11 +405,14 @@ function validateCommandPositionals(command_name, command_positionals) {
401
405
  };
402
406
  }
403
407
 
404
- if (command_name === 'show' && command_definition.missing_argument_label) {
408
+ if (
409
+ (command_name === 'refs' || command_name === 'show') &&
410
+ command_definition.missing_argument_label
411
+ ) {
405
412
  return {
406
413
  argument_label: command_definition.missing_argument_label,
407
414
  code: 'missing_required_argument',
408
- command_name: 'show',
415
+ command_name,
409
416
  };
410
417
  }
411
418
 
@@ -422,7 +429,7 @@ function validateCommandPositionals(command_name, command_positionals) {
422
429
 
423
430
  if (command_name === 'query' && command_positionals.length === 0) {
424
431
  return {
425
- argument_label: '<name> or --where "<clause>"',
432
+ argument_label: "<name> or --where '<clause>'",
426
433
  code: 'missing_required_argument',
427
434
  command_name: 'query',
428
435
  };
@@ -1,9 +1,9 @@
1
1
  /* eslint-disable max-lines-per-function */
2
2
  /**
3
- * @typedef {import('./parse-cli-arguments-helpers.js').CliOptionValues} CliOptionValues
4
- * @typedef {import('./parse-cli-arguments-helpers.js').ParsedCommandLine} ParsedCommandLine
5
- * @typedef {import('./parse-cli-arguments.types.ts').CliParseError} CliParseError
6
- * @typedef {import('./parse-cli-arguments.types.ts').ParseCliArgumentsResult} ParseCliArgumentsResult
3
+ * @typedef {import('./parse-arguments-helpers.js').CliOptionValues} CliOptionValues
4
+ * @typedef {import('./parse-arguments-helpers.js').ParsedCommandLine} ParsedCommandLine
5
+ * @typedef {import('./arguments.types.ts').CliParseError} CliParseError
6
+ * @typedef {import('./arguments.types.ts').ParseCliArgumentsResult} ParseCliArgumentsResult
7
7
  */
8
8
 
9
9
  import { parseArgs } from 'node:util';
@@ -23,10 +23,10 @@ import {
23
23
  validateHelpCommandLine,
24
24
  validateParsedCommand,
25
25
  validateRootCommandLine,
26
- } from './parse-cli-arguments-helpers.js';
27
- import { isCommandName } from './cli-help-metadata.js';
28
- import { resolveColorMode } from './parse-cli-color-options.js';
29
- import { buildQueryPagination } from './parse-cli-query-pagination.js';
26
+ } from './parse-arguments-helpers.js';
27
+ import { isCommandName } from './help-metadata.js';
28
+ import { resolveColorMode } from './color-options.js';
29
+ import { buildQueryPagination } from './query-pagination.js';
30
30
 
31
31
  /**
32
32
  * CLI argument parsing.
@@ -36,11 +36,11 @@ import { buildQueryPagination } from './parse-cli-query-pagination.js';
36
36
  *
37
37
  * Kind: cli
38
38
  * Status: active
39
- * Tracked in: ../docs/plans/v0/source-anchor-dogfooding.md
40
- * Decided by: ../docs/decisions/cli-argument-parser.md
39
+ * Tracked in: ../../docs/plans/v0/source-anchor-dogfooding.md
40
+ * Decided by: ../../docs/decisions/cli-argument-parser.md
41
41
  * @patram
42
- * @see {@link ./patram-cli.js}
43
- * @see {@link ../docs/decisions/cli-argument-parser.md}
42
+ * @see {@link ./main.js}
43
+ * @see {@link ../../docs/decisions/cli-argument-parser.md}
44
44
  */
45
45
 
46
46
  /**
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @typedef {import('./parse-cli-arguments-helpers.js').CliOptionToken} CliOptionToken
3
- * @typedef {import('./parse-cli-arguments-helpers.js').CliOptionValues} CliOptionValues
2
+ * @typedef {import('./parse-arguments-helpers.js').CliOptionToken} CliOptionToken
3
+ * @typedef {import('./parse-arguments-helpers.js').CliOptionValues} CliOptionValues
4
4
  */
5
5
 
6
6
  /**
@@ -5,8 +5,8 @@
5
5
  * CliHelpTopicName,
6
6
  * CliParseError,
7
7
  * ParsedCliHelpRequest,
8
- * } from './parse-cli-arguments.types.ts';
9
- * @import { PatramDiagnostic } from './load-patram-config.types.ts';
8
+ * } from './arguments.types.ts';
9
+ * @import { PatramDiagnostic } from '../config/load-patram-config.types.ts';
10
10
  */
11
11
 
12
12
  import {
@@ -15,7 +15,7 @@ import {
15
15
  getRootHelpDefinition,
16
16
  listCommandNames,
17
17
  listHelpTopicNames,
18
- } from './cli-help-metadata.js';
18
+ } from './help-metadata.js';
19
19
 
20
20
  /**
21
21
  * @param {ParsedCliHelpRequest} help_request
@@ -308,7 +308,7 @@ function renderInvalidCommandOptionError(command_name, invalid_token) {
308
308
  }
309
309
 
310
310
  /**
311
- * @param {'query' | 'show'} command_name
311
+ * @param {'query' | 'refs' | 'show'} command_name
312
312
  * @param {string} argument_label
313
313
  * @returns {string}
314
314
  */
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @import { ParsedCliArguments } from './parse-cli-arguments.types.ts';
3
- * @import { ResolvedOutputMode } from './output-view.types.ts';
2
+ * @import { ParsedCliArguments } from './arguments.types.ts';
3
+ * @import { ResolvedOutputMode } from '../output/output-view.types.ts';
4
4
  */
5
5
 
6
6
  /**
@@ -0,0 +1,30 @@
1
+ export function createIoContext() {
2
+ /** @type {{ stderr_chunks: string[], stdout_chunks: string[] }} */
3
+ const io_context = {
4
+ stderr_chunks: [],
5
+ stdout_chunks: [],
6
+ };
7
+
8
+ return {
9
+ ...io_context,
10
+ stderr: {
11
+ /**
12
+ * @param {string} chunk
13
+ */
14
+ write(chunk) {
15
+ io_context.stderr_chunks.push(chunk);
16
+ return true;
17
+ },
18
+ },
19
+ stdout: {
20
+ isTTY: false,
21
+ /**
22
+ * @param {string} chunk
23
+ */
24
+ write(chunk) {
25
+ io_context.stdout_chunks.push(chunk);
26
+ return true;
27
+ },
28
+ },
29
+ };
30
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * @returns {PatramRepoConfig}
3
+ */
4
+ export function createDefaultRepoConfig(): PatramRepoConfig;
5
+ /**
6
+ * @param {PatramRepoConfig} repo_config
7
+ * @returns {PatramRepoConfig}
8
+ */
9
+ export function normalizeRepoConfig(repo_config: PatramRepoConfig): PatramRepoConfig;
10
+ import type { PatramRepoConfig } from './schema.js';
@@ -0,0 +1,80 @@
1
+ /**
2
+ * @import { PatramRepoConfig } from './schema.js';
3
+ */
4
+
5
+ import { DEFAULT_INCLUDE_PATTERNS } from './source-file-defaults.js';
6
+
7
+ /**
8
+ * @returns {PatramRepoConfig}
9
+ */
10
+ export function createDefaultRepoConfig() {
11
+ return {
12
+ include: [...DEFAULT_INCLUDE_PATTERNS],
13
+ queries: {},
14
+ };
15
+ }
16
+
17
+ /**
18
+ * @param {PatramRepoConfig} repo_config
19
+ * @returns {PatramRepoConfig}
20
+ */
21
+ export function normalizeRepoConfig(repo_config) {
22
+ /** @type {PatramRepoConfig} */
23
+ const normalized_config = {
24
+ include: [...repo_config.include],
25
+ queries: { ...repo_config.queries },
26
+ };
27
+
28
+ assignOptionalRepoConfigField(
29
+ normalized_config,
30
+ 'classes',
31
+ repo_config.classes,
32
+ );
33
+ assignOptionalRepoConfigField(
34
+ normalized_config,
35
+ 'derived_summaries',
36
+ repo_config.derived_summaries,
37
+ );
38
+ assignOptionalRepoConfigField(
39
+ normalized_config,
40
+ 'fields',
41
+ repo_config.fields,
42
+ );
43
+ assignOptionalRepoConfigField(
44
+ normalized_config,
45
+ 'mappings',
46
+ repo_config.mappings,
47
+ );
48
+ assignOptionalRepoConfigField(
49
+ normalized_config,
50
+ 'path_classes',
51
+ repo_config.path_classes,
52
+ );
53
+ assignOptionalRepoConfigField(
54
+ normalized_config,
55
+ 'relations',
56
+ repo_config.relations,
57
+ );
58
+
59
+ return normalized_config;
60
+ }
61
+
62
+ /**
63
+ * @template {Exclude<keyof PatramRepoConfig, 'include' | 'queries'>} TKey
64
+ * @param {PatramRepoConfig} normalized_config
65
+ * @param {TKey} field_name
66
+ * @param {unknown} field_value
67
+ */
68
+ function assignOptionalRepoConfigField(
69
+ normalized_config,
70
+ field_name,
71
+ field_value,
72
+ ) {
73
+ if (field_value === undefined || field_value === null) {
74
+ return;
75
+ }
76
+
77
+ normalized_config[field_name] = /** @type {PatramRepoConfig[TKey]} */ (
78
+ field_value
79
+ );
80
+ }
@@ -0,0 +1,76 @@
1
+ /**
2
+ * Repo config loading.
3
+ *
4
+ * Reads `.patram.json`, applies defaults, and validates repo config and graph
5
+ * schema before command execution.
6
+ *
7
+ * Kind: config
8
+ * Status: active
9
+ * Tracked in: ../../docs/plans/v0/source-anchor-dogfooding.md
10
+ * Decided by: ../../docs/decisions/single-config-file.md
11
+ * Decided by: ../../docs/decisions/optional-config-default-scan.md
12
+ * @patram
13
+ * @see {@link ./schema.js}
14
+ * @see {@link ./validation.js}
15
+ */
16
+ /**
17
+ * @typedef {object} PatramDiagnostic
18
+ * @property {string} code
19
+ * @property {number} column
20
+ * @property {'error'} level
21
+ * @property {number} line
22
+ * @property {string} message
23
+ * @property {string} path
24
+ */
25
+ /**
26
+ * @typedef {object} LoadPatramConfigResult
27
+ * @property {import('./schema.js').PatramRepoConfig | null} config
28
+ * @property {string} config_path
29
+ * @property {PatramDiagnostic[]} diagnostics
30
+ */
31
+ /**
32
+ * @typedef {import('./schema.js').StoredQueryConfig} StoredQueryConfig
33
+ * @typedef {import('./schema.js').FieldDisplayConfig} FieldDisplayConfig
34
+ * @typedef {import('./schema.js').FieldQueryConfig} FieldQueryConfig
35
+ * @typedef {import('./schema.js').MetadataFieldConfig} MetadataFieldConfig
36
+ * @typedef {import('./schema.js').ClassFieldRuleConfig} ClassFieldRuleConfig
37
+ * @typedef {import('./schema.js').ClassSchemaConfig} ClassSchemaConfig
38
+ * @typedef {import('./schema.js').PathClassConfig} PathClassConfig
39
+ * @typedef {import('./schema.js').DerivedSummaryScalar} DerivedSummaryScalar
40
+ * @typedef {import('./schema.js').DerivedSummarySelectCaseConfig} DerivedSummarySelectCaseConfig
41
+ * @typedef {import('./schema.js').DerivedSummaryFieldConfig} DerivedSummaryFieldConfig
42
+ * @typedef {import('./schema.js').DerivedSummaryConfig} DerivedSummaryConfig
43
+ * @typedef {import('./schema.js').PatramRepoConfig} PatramRepoConfig
44
+ */
45
+ /**
46
+ * Load and validate the repo Patram config.
47
+ *
48
+ * @param {string} [project_directory]
49
+ * @returns {Promise<LoadPatramConfigResult>}
50
+ */
51
+ export function loadPatramConfig(project_directory?: string): Promise<LoadPatramConfigResult>;
52
+ export type PatramDiagnostic = {
53
+ code: string;
54
+ column: number;
55
+ level: "error";
56
+ line: number;
57
+ message: string;
58
+ path: string;
59
+ };
60
+ export type LoadPatramConfigResult = {
61
+ config: import("./schema.js").PatramRepoConfig | null;
62
+ config_path: string;
63
+ diagnostics: PatramDiagnostic[];
64
+ };
65
+ export type StoredQueryConfig = import("./schema.js").StoredQueryConfig;
66
+ export type FieldDisplayConfig = import("./schema.js").FieldDisplayConfig;
67
+ export type FieldQueryConfig = import("./schema.js").FieldQueryConfig;
68
+ export type MetadataFieldConfig = import("./schema.js").MetadataFieldConfig;
69
+ export type ClassFieldRuleConfig = import("./schema.js").ClassFieldRuleConfig;
70
+ export type ClassSchemaConfig = import("./schema.js").ClassSchemaConfig;
71
+ export type PathClassConfig = import("./schema.js").PathClassConfig;
72
+ export type DerivedSummaryScalar = import("./schema.js").DerivedSummaryScalar;
73
+ export type DerivedSummarySelectCaseConfig = import("./schema.js").DerivedSummarySelectCaseConfig;
74
+ export type DerivedSummaryFieldConfig = import("./schema.js").DerivedSummaryFieldConfig;
75
+ export type DerivedSummaryConfig = import("./schema.js").DerivedSummaryConfig;
76
+ export type PatramRepoConfig = import("./schema.js").PatramRepoConfig;