@unbrained/pm-cli 2026.5.18 → 2026.5.24

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 (225) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/README.md +2 -1
  3. package/dist/cli/commander-usage.js +16 -2
  4. package/dist/cli/commander-usage.js.map +1 -1
  5. package/dist/cli/commands/annotation-command.d.ts +49 -0
  6. package/dist/cli/commands/annotation-command.js +135 -0
  7. package/dist/cli/commands/annotation-command.js.map +1 -0
  8. package/dist/cli/commands/append.js +3 -7
  9. package/dist/cli/commands/append.js.map +1 -1
  10. package/dist/cli/commands/calendar.js +3 -6
  11. package/dist/cli/commands/calendar.js.map +1 -1
  12. package/dist/cli/commands/claim.js +12 -22
  13. package/dist/cli/commands/claim.js.map +1 -1
  14. package/dist/cli/commands/close.js +61 -9
  15. package/dist/cli/commands/close.js.map +1 -1
  16. package/dist/cli/commands/comments.d.ts +5 -0
  17. package/dist/cli/commands/comments.js +27 -117
  18. package/dist/cli/commands/comments.js.map +1 -1
  19. package/dist/cli/commands/completion.js +102 -15
  20. package/dist/cli/commands/completion.js.map +1 -1
  21. package/dist/cli/commands/context.js +4 -10
  22. package/dist/cli/commands/context.js.map +1 -1
  23. package/dist/cli/commands/contracts.js +168 -36
  24. package/dist/cli/commands/contracts.js.map +1 -1
  25. package/dist/cli/commands/create.js +49 -44
  26. package/dist/cli/commands/create.js.map +1 -1
  27. package/dist/cli/commands/dedupe-audit.js +7 -4
  28. package/dist/cli/commands/dedupe-audit.js.map +1 -1
  29. package/dist/cli/commands/delete.d.ts +3 -0
  30. package/dist/cli/commands/delete.js +9 -8
  31. package/dist/cli/commands/delete.js.map +1 -1
  32. package/dist/cli/commands/docs.d.ts +1 -0
  33. package/dist/cli/commands/docs.js +4 -8
  34. package/dist/cli/commands/docs.js.map +1 -1
  35. package/dist/cli/commands/event-validation-messages.d.ts +3 -0
  36. package/dist/cli/commands/event-validation-messages.js +44 -0
  37. package/dist/cli/commands/event-validation-messages.js.map +1 -0
  38. package/dist/cli/commands/extension.d.ts +1 -0
  39. package/dist/cli/commands/extension.js +138 -21
  40. package/dist/cli/commands/extension.js.map +1 -1
  41. package/dist/cli/commands/files.js +6 -13
  42. package/dist/cli/commands/files.js.map +1 -1
  43. package/dist/cli/commands/gc.js +17 -4
  44. package/dist/cli/commands/gc.js.map +1 -1
  45. package/dist/cli/commands/get.d.ts +3 -2
  46. package/dist/cli/commands/get.js +50 -8
  47. package/dist/cli/commands/get.js.map +1 -1
  48. package/dist/cli/commands/health.d.ts +10 -0
  49. package/dist/cli/commands/health.js +254 -75
  50. package/dist/cli/commands/health.js.map +1 -1
  51. package/dist/cli/commands/history-redact.d.ts +8 -0
  52. package/dist/cli/commands/history-redact.js +14 -97
  53. package/dist/cli/commands/history-redact.js.map +1 -1
  54. package/dist/cli/commands/history-repair.d.ts +33 -0
  55. package/dist/cli/commands/history-repair.js +166 -0
  56. package/dist/cli/commands/history-repair.js.map +1 -0
  57. package/dist/cli/commands/history.d.ts +4 -4
  58. package/dist/cli/commands/history.js +10 -88
  59. package/dist/cli/commands/history.js.map +1 -1
  60. package/dist/cli/commands/index.d.ts +3 -1
  61. package/dist/cli/commands/index.js +5 -3
  62. package/dist/cli/commands/index.js.map +1 -1
  63. package/dist/cli/commands/init.d.ts +28 -0
  64. package/dist/cli/commands/init.js +23 -2
  65. package/dist/cli/commands/init.js.map +1 -1
  66. package/dist/cli/commands/learnings.js +20 -119
  67. package/dist/cli/commands/learnings.js.map +1 -1
  68. package/dist/cli/commands/linked-test-entry.d.ts +3 -0
  69. package/dist/cli/commands/linked-test-entry.js +62 -0
  70. package/dist/cli/commands/linked-test-entry.js.map +1 -0
  71. package/dist/cli/commands/list.js +32 -22
  72. package/dist/cli/commands/list.js.map +1 -1
  73. package/dist/cli/commands/notes.js +20 -119
  74. package/dist/cli/commands/notes.js.map +1 -1
  75. package/dist/cli/commands/plan.d.ts +3 -0
  76. package/dist/cli/commands/plan.js +184 -22
  77. package/dist/cli/commands/plan.js.map +1 -1
  78. package/dist/cli/commands/restore.js +7 -50
  79. package/dist/cli/commands/restore.js.map +1 -1
  80. package/dist/cli/commands/schema.d.ts +31 -0
  81. package/dist/cli/commands/schema.js +98 -0
  82. package/dist/cli/commands/schema.js.map +1 -0
  83. package/dist/cli/commands/search.js +151 -40
  84. package/dist/cli/commands/search.js.map +1 -1
  85. package/dist/cli/commands/templates.d.ts +4 -0
  86. package/dist/cli/commands/templates.js +89 -17
  87. package/dist/cli/commands/templates.js.map +1 -1
  88. package/dist/cli/commands/test-all.js +4 -8
  89. package/dist/cli/commands/test-all.js.map +1 -1
  90. package/dist/cli/commands/test.d.ts +1 -0
  91. package/dist/cli/commands/test.js +7 -10
  92. package/dist/cli/commands/test.js.map +1 -1
  93. package/dist/cli/commands/update-many.js +4 -8
  94. package/dist/cli/commands/update-many.js.map +1 -1
  95. package/dist/cli/commands/update.js +109 -51
  96. package/dist/cli/commands/update.js.map +1 -1
  97. package/dist/cli/commands/validate.d.ts +3 -1
  98. package/dist/cli/commands/validate.js +23 -71
  99. package/dist/cli/commands/validate.js.map +1 -1
  100. package/dist/cli/error-guidance.js +96 -6
  101. package/dist/cli/error-guidance.js.map +1 -1
  102. package/dist/cli/extension-command-help.d.ts +0 -1
  103. package/dist/cli/extension-command-help.js +2 -13
  104. package/dist/cli/extension-command-help.js.map +1 -1
  105. package/dist/cli/extension-command-options.d.ts +1 -0
  106. package/dist/cli/extension-command-options.js +106 -7
  107. package/dist/cli/extension-command-options.js.map +1 -1
  108. package/dist/cli/help-content.d.ts +0 -1
  109. package/dist/cli/help-content.js +13 -9
  110. package/dist/cli/help-content.js.map +1 -1
  111. package/dist/cli/help-json-payload.d.ts +1 -0
  112. package/dist/cli/help-json-payload.js +33 -3
  113. package/dist/cli/help-json-payload.js.map +1 -1
  114. package/dist/cli/main.js +35 -29
  115. package/dist/cli/main.js.map +1 -1
  116. package/dist/cli/register-list-query.d.ts +1 -1
  117. package/dist/cli/register-list-query.js +40 -17
  118. package/dist/cli/register-list-query.js.map +1 -1
  119. package/dist/cli/register-mutation.d.ts +1 -1
  120. package/dist/cli/register-mutation.js +232 -64
  121. package/dist/cli/register-mutation.js.map +1 -1
  122. package/dist/cli/register-operations.js +16 -11
  123. package/dist/cli/register-operations.js.map +1 -1
  124. package/dist/cli/register-setup.js +26 -14
  125. package/dist/cli/register-setup.js.map +1 -1
  126. package/dist/cli/registration-helpers.d.ts +0 -2
  127. package/dist/cli/registration-helpers.js +13 -40
  128. package/dist/cli/registration-helpers.js.map +1 -1
  129. package/dist/cli.js +23 -3
  130. package/dist/cli.js.map +1 -1
  131. package/dist/core/extensions/index.d.ts +0 -1
  132. package/dist/core/extensions/index.js +2 -14
  133. package/dist/core/extensions/index.js.map +1 -1
  134. package/dist/core/extensions/loader.js +3 -9
  135. package/dist/core/extensions/loader.js.map +1 -1
  136. package/dist/core/fs/path-utils.d.ts +1 -0
  137. package/dist/core/fs/path-utils.js +12 -0
  138. package/dist/core/fs/path-utils.js.map +1 -0
  139. package/dist/core/history/drift-scan.d.ts +11 -0
  140. package/dist/core/history/drift-scan.js +67 -0
  141. package/dist/core/history/drift-scan.js.map +1 -0
  142. package/dist/core/history/replay.d.ts +82 -0
  143. package/dist/core/history/replay.js +249 -0
  144. package/dist/core/history/replay.js.map +1 -0
  145. package/dist/core/item/item-format.js +11 -8
  146. package/dist/core/item/item-format.js.map +1 -1
  147. package/dist/core/item/item-type-definition.d.ts +52 -0
  148. package/dist/core/item/item-type-definition.js +123 -0
  149. package/dist/core/item/item-type-definition.js.map +1 -0
  150. package/dist/core/item/parse.js +3 -2
  151. package/dist/core/item/parse.js.map +1 -1
  152. package/dist/core/item/priority.d.ts +23 -0
  153. package/dist/core/item/priority.js +55 -0
  154. package/dist/core/item/priority.js.map +1 -0
  155. package/dist/core/item/status.d.ts +14 -1
  156. package/dist/core/item/status.js +22 -2
  157. package/dist/core/item/status.js.map +1 -1
  158. package/dist/core/item/toon-decode.d.ts +19 -0
  159. package/dist/core/item/toon-decode.js +69 -0
  160. package/dist/core/item/toon-decode.js.map +1 -0
  161. package/dist/core/item/type-registry.js +13 -84
  162. package/dist/core/item/type-registry.js.map +1 -1
  163. package/dist/core/packages/manifest.js +3 -9
  164. package/dist/core/packages/manifest.js.map +1 -1
  165. package/dist/core/schema/item-types-file.d.ts +85 -0
  166. package/dist/core/schema/item-types-file.js +243 -0
  167. package/dist/core/schema/item-types-file.js.map +1 -0
  168. package/dist/core/schema/runtime-schema.d.ts +2 -1
  169. package/dist/core/schema/runtime-schema.js +11 -9
  170. package/dist/core/schema/runtime-schema.js.map +1 -1
  171. package/dist/core/search/semantic-defaults.js +3 -3
  172. package/dist/core/search/semantic-defaults.js.map +1 -1
  173. package/dist/core/shared/author.d.ts +1 -0
  174. package/dist/core/shared/author.js +9 -0
  175. package/dist/core/shared/author.js.map +1 -0
  176. package/dist/core/shared/lazy-module.d.ts +1 -0
  177. package/dist/core/shared/lazy-module.js +11 -0
  178. package/dist/core/shared/lazy-module.js.map +1 -0
  179. package/dist/core/shared/option-alias-visibility.d.ts +44 -0
  180. package/dist/core/shared/option-alias-visibility.js +76 -0
  181. package/dist/core/shared/option-alias-visibility.js.map +1 -0
  182. package/dist/core/shared/text-normalization.d.ts +0 -1
  183. package/dist/core/shared/text-normalization.js +2 -5
  184. package/dist/core/shared/text-normalization.js.map +1 -1
  185. package/dist/core/store/item-store.d.ts +2 -0
  186. package/dist/core/store/item-store.js +70 -39
  187. package/dist/core/store/item-store.js.map +1 -1
  188. package/dist/core/store/settings-validator.d.ts +106 -0
  189. package/dist/core/store/settings-validator.js +279 -0
  190. package/dist/core/store/settings-validator.js.map +1 -0
  191. package/dist/core/store/settings.js +6 -343
  192. package/dist/core/store/settings.js.map +1 -1
  193. package/dist/core/telemetry/runtime.js +5 -3
  194. package/dist/core/telemetry/runtime.js.map +1 -1
  195. package/dist/mcp/server.js +64 -13
  196. package/dist/mcp/server.js.map +1 -1
  197. package/dist/sdk/cli-contracts.d.ts +9 -2
  198. package/dist/sdk/cli-contracts.js +204 -13
  199. package/dist/sdk/cli-contracts.js.map +1 -1
  200. package/dist/sdk/runtime.d.ts +25 -1
  201. package/dist/sdk/runtime.js +46 -3
  202. package/dist/sdk/runtime.js.map +1 -1
  203. package/dist/types.d.ts +6 -0
  204. package/dist/types.js +10 -2
  205. package/dist/types.js.map +1 -1
  206. package/docs/AGENT_GUIDE.md +7 -1
  207. package/docs/ARCHITECTURE.md +1 -1
  208. package/docs/COMMANDS.md +39 -6
  209. package/docs/CONFIGURATION.md +1 -1
  210. package/docs/RELEASING.md +11 -7
  211. package/docs/SDK.md +11 -2
  212. package/package.json +12 -11
  213. package/packages/pm-calendar/README.md +3 -1
  214. package/packages/pm-calendar/extensions/calendar/index.js +21 -2
  215. package/packages/pm-calendar/extensions/calendar/index.ts +21 -2
  216. package/packages/pm-search-advanced/README.md +8 -0
  217. package/packages/pm-search-advanced/extensions/search-advanced/index.js +74 -0
  218. package/packages/pm-search-advanced/extensions/search-advanced/index.ts +74 -0
  219. package/packages/pm-search-advanced/extensions/search-advanced/runtime.js +67 -9
  220. package/packages/pm-search-advanced/extensions/search-advanced/runtime.ts +67 -9
  221. package/packages/pm-templates/extensions/templates/runtime.js +11 -202
  222. package/packages/pm-templates/extensions/templates/runtime.ts +38 -230
  223. package/dist/core/output/command-aware.d.ts +0 -1
  224. package/dist/core/output/command-aware.js +0 -397
  225. package/dist/core/output/command-aware.js.map +0 -1
@@ -23,7 +23,7 @@ const calendarFlags = [
23
23
  { long: "--assignee-filter", value_name: "value", value_type: "string", description: "Filter assignee presence." },
24
24
  { long: "--sprint", value_name: "value", value_type: "string", description: "Filter by sprint." },
25
25
  { long: "--release", value_name: "value", value_type: "string", description: "Filter by release." },
26
- { long: "--include", value_name: "value", value_type: "string", description: "Include sources: deadlines|reminders|events|all." },
26
+ { long: "--include", value_name: "value", value_type: "string", description: "Include sources: deadlines|reminders|events|scheduled|all." },
27
27
  { long: "--recurrence-lookahead-days", value_name: "n", value_type: "string", description: "Bound open-ended recurrence lookahead days." },
28
28
  { long: "--recurrence-lookback-days", value_name: "n", value_type: "string", description: "Bound open-ended recurrence lookback days." },
29
29
  { long: "--occurrence-limit", value_name: "n", value_type: "string", description: "Cap generated occurrences per recurring event." },
@@ -36,8 +36,27 @@ function calendarCommand(name) {
36
36
  name,
37
37
  action: "calendar",
38
38
  description: "Show deadline, reminder, and scheduled event calendar views.",
39
+ arguments: [{ name: "view", required: false, description: "Calendar view: agenda|day|week|month." }],
39
40
  flags: [...calendarFlags],
40
- run: async (context) => runCalendarPackage(context.options, context.global),
41
+ run: async (context) => {
42
+ // Extension flags are parsed loosely, so context.args still contains flag
43
+ // tokens (e.g. ["day", "--date", "+7d"]). Only the leading non-flag tokens
44
+ // are true positionals, so a positional view combined with --date/--from/etc.
45
+ // must not be mistaken for multiple positional views.
46
+ const firstFlagIndex = context.args.findIndex((arg) => arg.startsWith("-"));
47
+ const positionalArgs = firstFlagIndex === -1 ? context.args : context.args.slice(0, firstFlagIndex);
48
+ const positionalView = positionalArgs[0]?.trim();
49
+ if (positionalArgs.length > 1) {
50
+ throw new Error("Calendar accepts at most one positional view: agenda|day|week|month.");
51
+ }
52
+ return runCalendarPackage(
53
+ {
54
+ ...context.options,
55
+ ...(positionalView && context.options.view === undefined ? { view: positionalView } : {}),
56
+ },
57
+ context.global,
58
+ );
59
+ },
41
60
  };
42
61
  }
43
62
 
@@ -29,7 +29,7 @@ const calendarFlags = [
29
29
  { long: "--assignee-filter", value_name: "value", value_type: "string", description: "Filter assignee presence." },
30
30
  { long: "--sprint", value_name: "value", value_type: "string", description: "Filter by sprint." },
31
31
  { long: "--release", value_name: "value", value_type: "string", description: "Filter by release." },
32
- { long: "--include", value_name: "value", value_type: "string", description: "Include sources: deadlines|reminders|events|all." },
32
+ { long: "--include", value_name: "value", value_type: "string", description: "Include sources: deadlines|reminders|events|scheduled|all." },
33
33
  { long: "--recurrence-lookahead-days", value_name: "n", value_type: "string", description: "Bound open-ended recurrence lookahead days." },
34
34
  { long: "--recurrence-lookback-days", value_name: "n", value_type: "string", description: "Bound open-ended recurrence lookback days." },
35
35
  { long: "--occurrence-limit", value_name: "n", value_type: "string", description: "Cap generated occurrences per recurring event." },
@@ -42,8 +42,27 @@ function calendarCommand(name: "calendar" | "cal"): CommandDefinition {
42
42
  name,
43
43
  action: "calendar",
44
44
  description: "Show deadline, reminder, and scheduled event calendar views.",
45
+ arguments: [{ name: "view", required: false, description: "Calendar view: agenda|day|week|month." }],
45
46
  flags: [...calendarFlags],
46
- run: async (context) => runCalendarPackage(context.options as CalendarOptions, context.global),
47
+ run: async (context) => {
48
+ // Extension flags are parsed loosely, so context.args still contains flag
49
+ // tokens (e.g. ["day", "--date", "+7d"]). Only the leading non-flag tokens
50
+ // are true positionals, so a positional view combined with --date/--from/etc.
51
+ // must not be mistaken for multiple positional views.
52
+ const firstFlagIndex = context.args.findIndex((arg) => arg.startsWith("-"));
53
+ const positionalArgs = firstFlagIndex === -1 ? context.args : context.args.slice(0, firstFlagIndex);
54
+ const positionalView = positionalArgs[0]?.trim();
55
+ if (positionalArgs.length > 1) {
56
+ throw new Error("Calendar accepts at most one positional view: agenda|day|week|month.");
57
+ }
58
+ return runCalendarPackage(
59
+ {
60
+ ...(context.options as CalendarOptions),
61
+ ...(positionalView && (context.options as CalendarOptions).view === undefined ? { view: positionalView } : {}),
62
+ },
63
+ context.global,
64
+ );
65
+ },
47
66
  };
48
67
  }
49
68
 
@@ -6,9 +6,13 @@ First-party package that restores optional advanced search surfaces in bare-core
6
6
 
7
7
  - Adds `pm search-advanced` with:
8
8
  - `--mode keyword|semantic|hybrid`
9
+ - `--semantic`, `--hybrid`
9
10
  - `--include-linked`
10
11
  - `--title-exact`
11
12
  - `--phrase-exact`
13
+ - `--type`, `--tag`, `--priority`
14
+ - `--deadline-before`, `--deadline-after`
15
+ - `--limit`, `--fields`, `--compact`, `--full`
12
16
  - Adds `pm reindex` with:
13
17
  - `--mode keyword|semantic|hybrid`
14
18
  - `--progress`
@@ -23,5 +27,9 @@ pm install search-advanced --project
23
27
 
24
28
  ```bash
25
29
  pm search-advanced "vector cache" --mode hybrid --limit 5 --json
30
+ pm search-advanced --hybrid "vector cache" --limit 5 --json
31
+ pm search-advanced "calendar package" --mode keyword --fields id,title,score --compact --json
26
32
  pm reindex --mode hybrid --progress --json
27
33
  ```
34
+
35
+ Without `--mode`, `--semantic`, or `--hybrid`, `search-advanced` stays keyword-first for fast agent reads.
@@ -15,6 +15,16 @@ const searchAdvancedFlags = [
15
15
  value_type: "string",
16
16
  description: "Search mode override: keyword|semantic|hybrid.",
17
17
  },
18
+ {
19
+ long: "--semantic",
20
+ value_type: "boolean",
21
+ description: "Alias for --mode semantic.",
22
+ },
23
+ {
24
+ long: "--hybrid",
25
+ value_type: "boolean",
26
+ description: "Alias for --mode hybrid.",
27
+ },
18
28
  {
19
29
  long: "--include-linked",
20
30
  value_type: "boolean",
@@ -45,6 +55,70 @@ const searchAdvancedFlags = [
45
55
  value_type: "boolean",
46
56
  description: "Alias for --phrase-exact.",
47
57
  },
58
+ {
59
+ long: "--type",
60
+ value_name: "value",
61
+ value_type: "string",
62
+ description: "Filter by item type.",
63
+ },
64
+ {
65
+ long: "--tag",
66
+ value_name: "value",
67
+ value_type: "string",
68
+ description: "Filter by tag.",
69
+ },
70
+ {
71
+ long: "--priority",
72
+ value_name: "value",
73
+ value_type: "string",
74
+ description: "Filter by priority.",
75
+ },
76
+ {
77
+ long: "--deadline-before",
78
+ value_name: "date",
79
+ value_type: "string",
80
+ description: "Filter to items with deadlines before a date.",
81
+ },
82
+ {
83
+ long: "--deadline_before",
84
+ value_name: "date",
85
+ value_type: "string",
86
+ description: "Alias for --deadline-before.",
87
+ },
88
+ {
89
+ long: "--deadline-after",
90
+ value_name: "date",
91
+ value_type: "string",
92
+ description: "Filter to items with deadlines after a date.",
93
+ },
94
+ {
95
+ long: "--deadline_after",
96
+ value_name: "date",
97
+ value_type: "string",
98
+ description: "Alias for --deadline-after.",
99
+ },
100
+ {
101
+ long: "--limit",
102
+ value_name: "count",
103
+ value_type: "string",
104
+ description: "Limit the number of search results.",
105
+ },
106
+ {
107
+ long: "--fields",
108
+ value_name: "list",
109
+ value_type: "string",
110
+ description: "Return only selected result fields.",
111
+ },
112
+ {
113
+ long: "--compact",
114
+ value_type: "boolean",
115
+ description: "Return compact token-efficient search results.",
116
+ },
117
+ {
118
+ long: "--full",
119
+ value_type: "boolean",
120
+ description: "Return full search results.",
121
+ },
48
122
  ];
49
123
 
50
124
  const reindexFlags = [
@@ -16,6 +16,16 @@ const searchAdvancedFlags = [
16
16
  value_type: "string",
17
17
  description: "Search mode override: keyword|semantic|hybrid.",
18
18
  },
19
+ {
20
+ long: "--semantic",
21
+ value_type: "boolean",
22
+ description: "Alias for --mode semantic.",
23
+ },
24
+ {
25
+ long: "--hybrid",
26
+ value_type: "boolean",
27
+ description: "Alias for --mode hybrid.",
28
+ },
19
29
  {
20
30
  long: "--include-linked",
21
31
  value_type: "boolean",
@@ -46,6 +56,70 @@ const searchAdvancedFlags = [
46
56
  value_type: "boolean",
47
57
  description: "Alias for --phrase-exact.",
48
58
  },
59
+ {
60
+ long: "--type",
61
+ value_name: "value",
62
+ value_type: "string",
63
+ description: "Filter by item type.",
64
+ },
65
+ {
66
+ long: "--tag",
67
+ value_name: "value",
68
+ value_type: "string",
69
+ description: "Filter by tag.",
70
+ },
71
+ {
72
+ long: "--priority",
73
+ value_name: "value",
74
+ value_type: "string",
75
+ description: "Filter by priority.",
76
+ },
77
+ {
78
+ long: "--deadline-before",
79
+ value_name: "date",
80
+ value_type: "string",
81
+ description: "Filter to items with deadlines before a date.",
82
+ },
83
+ {
84
+ long: "--deadline_before",
85
+ value_name: "date",
86
+ value_type: "string",
87
+ description: "Alias for --deadline-before.",
88
+ },
89
+ {
90
+ long: "--deadline-after",
91
+ value_name: "date",
92
+ value_type: "string",
93
+ description: "Filter to items with deadlines after a date.",
94
+ },
95
+ {
96
+ long: "--deadline_after",
97
+ value_name: "date",
98
+ value_type: "string",
99
+ description: "Alias for --deadline-after.",
100
+ },
101
+ {
102
+ long: "--limit",
103
+ value_name: "count",
104
+ value_type: "string",
105
+ description: "Limit the number of search results.",
106
+ },
107
+ {
108
+ long: "--fields",
109
+ value_name: "list",
110
+ value_type: "string",
111
+ description: "Return only selected result fields.",
112
+ },
113
+ {
114
+ long: "--compact",
115
+ value_type: "boolean",
116
+ description: "Return compact token-efficient search results.",
117
+ },
118
+ {
119
+ long: "--full",
120
+ value_type: "boolean",
121
+ description: "Return full search results.",
122
+ },
49
123
  ] as const;
50
124
 
51
125
  const reindexFlags = [
@@ -48,6 +48,9 @@ function readStringOption(options, key, aliases = []) {
48
48
  return undefined;
49
49
  }
50
50
 
51
+ const BOOLEAN_TRUE_VALUES = new Set(["true", "1", "yes", "on"]);
52
+ const BOOLEAN_FALSE_VALUES = new Set(["false", "0", "no", "off"]);
53
+
51
54
  function readBooleanOption(options, key, aliases = []) {
52
55
  const keys = [key, ...aliases];
53
56
  for (const candidate of keys) {
@@ -60,10 +63,10 @@ function readBooleanOption(options, key, aliases = []) {
60
63
  }
61
64
  if (typeof value === "string") {
62
65
  const normalized = value.trim().toLowerCase();
63
- if (normalized === "true" || normalized === "1" || normalized === "yes" || normalized === "on") {
66
+ if (BOOLEAN_TRUE_VALUES.has(normalized)) {
64
67
  return true;
65
68
  }
66
- if (normalized === "false" || normalized === "0" || normalized === "no" || normalized === "off") {
69
+ if (BOOLEAN_FALSE_VALUES.has(normalized)) {
67
70
  return false;
68
71
  }
69
72
  }
@@ -71,24 +74,79 @@ function readBooleanOption(options, key, aliases = []) {
71
74
  return undefined;
72
75
  }
73
76
 
77
+ const SEARCH_VALUE_FLAGS = new Set([
78
+ "--mode",
79
+ "--type",
80
+ "--tag",
81
+ "--priority",
82
+ "--deadline-before",
83
+ "--deadline_before",
84
+ "--deadline-after",
85
+ "--deadline_after",
86
+ "--limit",
87
+ "--fields",
88
+ ]);
89
+
90
+ const SEARCH_BOOLEAN_FLAGS = new Set([
91
+ "--semantic",
92
+ "--hybrid",
93
+ "--include-linked",
94
+ "--include_linked",
95
+ "--title-exact",
96
+ "--title_exact",
97
+ "--phrase-exact",
98
+ "--phrase_exact",
99
+ "--compact",
100
+ "--full",
101
+ "--json",
102
+ ]);
103
+
104
+ function stripSearchOptionTokens(args) {
105
+ const queryTokens = [];
106
+ for (let index = 0; index < args.length; index += 1) {
107
+ const token = args[index]?.trim() ?? "";
108
+ const equalsIndex = token.indexOf("=");
109
+ const flagName = equalsIndex > 0 ? token.slice(0, equalsIndex) : token;
110
+ if (SEARCH_VALUE_FLAGS.has(flagName)) {
111
+ if (equalsIndex < 0) {
112
+ index += 1;
113
+ }
114
+ continue;
115
+ }
116
+ if (SEARCH_BOOLEAN_FLAGS.has(flagName)) {
117
+ continue;
118
+ }
119
+ if (token.length > 0) {
120
+ queryTokens.push(token);
121
+ }
122
+ }
123
+ return queryTokens;
124
+ }
125
+
74
126
  function resolveSearchQuery(args) {
75
- const query = args
76
- .map((value) => value.trim())
77
- .filter((value) => value.length > 0)
78
- .join(" ");
127
+ const query = stripSearchOptionTokens(args).join(" ");
79
128
  if (query.length === 0) {
80
129
  throw new PmCliError("Search query must not be empty", EXIT_CODE.USAGE);
81
130
  }
82
131
  return query;
83
132
  }
84
133
 
85
- function normalizeAdvancedSearchOptions(rawOptions) {
134
+ function normalizeAdvancedSearchOptions(rawOptions, args) {
86
135
  const fields = readStringOption(rawOptions, "fields");
87
136
  const compactRequested = readBooleanOption(rawOptions, "compact") === true;
88
137
  const fullRequested = readBooleanOption(rawOptions, "full") === true;
89
138
  const defaultCompact = !compactRequested && !fullRequested && fields === undefined;
139
+ const explicitMode = readStringOption(rawOptions, "mode");
140
+ const argFlags = new Set(args.map((value) => value?.trim() ?? ""));
141
+ const mode =
142
+ explicitMode ??
143
+ (readBooleanOption(rawOptions, "semantic") === true || argFlags.has("--semantic")
144
+ ? "semantic"
145
+ : readBooleanOption(rawOptions, "hybrid") === true || argFlags.has("--hybrid")
146
+ ? "hybrid"
147
+ : "keyword");
90
148
  return {
91
- mode: readStringOption(rawOptions, "mode"),
149
+ mode,
92
150
  includeLinked: readBooleanOption(rawOptions, "includeLinked", ["include_linked"]) === true ? true : undefined,
93
151
  titleExact: readBooleanOption(rawOptions, "titleExact", ["title_exact"]) === true ? true : undefined,
94
152
  phraseExact: readBooleanOption(rawOptions, "phraseExact", ["phrase_exact"]) === true ? true : undefined,
@@ -112,7 +170,7 @@ function normalizeReindexOptions(rawOptions) {
112
170
  }
113
171
 
114
172
  export async function runAdvancedSearchPackage(args, rawOptions, global) {
115
- return runSearch(resolveSearchQuery(args), normalizeAdvancedSearchOptions(rawOptions), global);
173
+ return runSearch(resolveSearchQuery(args), normalizeAdvancedSearchOptions(rawOptions, args), global);
116
174
  }
117
175
 
118
176
  export async function runAdvancedReindexPackage(rawOptions, global) {
@@ -65,6 +65,9 @@ function readStringOption(options: Record<string, unknown>, key: string, aliases
65
65
  return undefined;
66
66
  }
67
67
 
68
+ const BOOLEAN_TRUE_VALUES = new Set(["true", "1", "yes", "on"]);
69
+ const BOOLEAN_FALSE_VALUES = new Set(["false", "0", "no", "off"]);
70
+
68
71
  function readBooleanOption(options: Record<string, unknown>, key: string, aliases: string[] = []): boolean | undefined {
69
72
  const keys = [key, ...aliases];
70
73
  for (const candidate of keys) {
@@ -77,10 +80,10 @@ function readBooleanOption(options: Record<string, unknown>, key: string, aliase
77
80
  }
78
81
  if (typeof value === "string") {
79
82
  const normalized = value.trim().toLowerCase();
80
- if (normalized === "true" || normalized === "1" || normalized === "yes" || normalized === "on") {
83
+ if (BOOLEAN_TRUE_VALUES.has(normalized)) {
81
84
  return true;
82
85
  }
83
- if (normalized === "false" || normalized === "0" || normalized === "no" || normalized === "off") {
86
+ if (BOOLEAN_FALSE_VALUES.has(normalized)) {
84
87
  return false;
85
88
  }
86
89
  }
@@ -88,24 +91,79 @@ function readBooleanOption(options: Record<string, unknown>, key: string, aliase
88
91
  return undefined;
89
92
  }
90
93
 
94
+ const SEARCH_VALUE_FLAGS = new Set([
95
+ "--mode",
96
+ "--type",
97
+ "--tag",
98
+ "--priority",
99
+ "--deadline-before",
100
+ "--deadline_before",
101
+ "--deadline-after",
102
+ "--deadline_after",
103
+ "--limit",
104
+ "--fields",
105
+ ]);
106
+
107
+ const SEARCH_BOOLEAN_FLAGS = new Set([
108
+ "--semantic",
109
+ "--hybrid",
110
+ "--include-linked",
111
+ "--include_linked",
112
+ "--title-exact",
113
+ "--title_exact",
114
+ "--phrase-exact",
115
+ "--phrase_exact",
116
+ "--compact",
117
+ "--full",
118
+ "--json",
119
+ ]);
120
+
121
+ function stripSearchOptionTokens(args: string[]): string[] {
122
+ const queryTokens: string[] = [];
123
+ for (let index = 0; index < args.length; index += 1) {
124
+ const token = args[index]?.trim() ?? "";
125
+ const equalsIndex = token.indexOf("=");
126
+ const flagName = equalsIndex > 0 ? token.slice(0, equalsIndex) : token;
127
+ if (SEARCH_VALUE_FLAGS.has(flagName)) {
128
+ if (equalsIndex < 0) {
129
+ index += 1;
130
+ }
131
+ continue;
132
+ }
133
+ if (SEARCH_BOOLEAN_FLAGS.has(flagName)) {
134
+ continue;
135
+ }
136
+ if (token.length > 0) {
137
+ queryTokens.push(token);
138
+ }
139
+ }
140
+ return queryTokens;
141
+ }
142
+
91
143
  function resolveSearchQuery(args: string[]): string {
92
- const query = args
93
- .map((value) => value.trim())
94
- .filter((value) => value.length > 0)
95
- .join(" ");
144
+ const query = stripSearchOptionTokens(args).join(" ");
96
145
  if (query.length === 0) {
97
146
  throw new PmCliError("Search query must not be empty", EXIT_CODE.USAGE);
98
147
  }
99
148
  return query;
100
149
  }
101
150
 
102
- function normalizeAdvancedSearchOptions(rawOptions: Record<string, unknown>): SearchOptions {
151
+ function normalizeAdvancedSearchOptions(rawOptions: Record<string, unknown>, args: string[]): SearchOptions {
103
152
  const fields = readStringOption(rawOptions, "fields");
104
153
  const compactRequested = readBooleanOption(rawOptions, "compact") === true;
105
154
  const fullRequested = readBooleanOption(rawOptions, "full") === true;
106
155
  const defaultCompact = !compactRequested && !fullRequested && fields === undefined;
156
+ const explicitMode = readStringOption(rawOptions, "mode");
157
+ const argFlags = new Set(args.map((value) => value?.trim() ?? ""));
158
+ const mode =
159
+ explicitMode ??
160
+ (readBooleanOption(rawOptions, "semantic") === true || argFlags.has("--semantic")
161
+ ? "semantic"
162
+ : readBooleanOption(rawOptions, "hybrid") === true || argFlags.has("--hybrid")
163
+ ? "hybrid"
164
+ : "keyword");
107
165
  return {
108
- mode: readStringOption(rawOptions, "mode"),
166
+ mode,
109
167
  includeLinked: readBooleanOption(rawOptions, "includeLinked", ["include_linked"]) === true ? true : undefined,
110
168
  titleExact: readBooleanOption(rawOptions, "titleExact", ["title_exact"]) === true ? true : undefined,
111
169
  phraseExact: readBooleanOption(rawOptions, "phraseExact", ["phrase_exact"]) === true ? true : undefined,
@@ -133,7 +191,7 @@ export async function runAdvancedSearchPackage(
133
191
  rawOptions: Record<string, unknown>,
134
192
  global: GlobalOptions,
135
193
  ): Promise<SearchResult> {
136
- return runSearch(resolveSearchQuery(args), normalizeAdvancedSearchOptions(rawOptions), global);
194
+ return runSearch(resolveSearchQuery(args), normalizeAdvancedSearchOptions(rawOptions, args), global);
137
195
  }
138
196
 
139
197
  export async function runAdvancedReindexPackage(