@ted-galago/wave-cli 0.1.19 → 0.1.20

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.
package/README.md CHANGED
@@ -120,6 +120,7 @@ wave markdown-tree resolve --tool-key projects --node-key tasks --parent-id 123
120
120
  wave markdown-tree children --tool-key directory --node-key members --record-id 67
121
121
  wave markdown-tree subtree --tool-key knowledge --node-key knowledge --content-type processes --depth 2
122
122
  wave osmd tree
123
+ wave osmd search "Wave Tools" --scope combined --limit 10
123
124
  wave osmd read "projects/Wave Tools"
124
125
  wave osmd children "projects/Wave Tools"
125
126
  wave osmd status "projects/Wave Tools/.agent/notes.md" --parent-ref "projects/Wave Tools"
@@ -307,6 +308,7 @@ The `osmd` command group is the write-capable agent interface for canonical OSMD
307
308
  Commands:
308
309
 
309
310
  - `wave osmd tree [--depth <n>] [--tree-view]`
311
+ - `wave osmd search "<query>" [--scope os-only|agent-overlay-only|agent-wiki-only|combined] [--limit <n>]`
310
312
  - `wave osmd read <path> [--parent-ref <canonicalPath>]`
311
313
  - `wave osmd children [path] [--parent-ref <canonicalPath>] [--source canonical_osmd|agent_overlay|agent_wiki]`
312
314
  - `wave osmd status <path> [--parent-ref <canonicalPath>]`
@@ -326,6 +328,7 @@ Commands:
326
328
  GraphQL mapping:
327
329
 
328
330
  - `osmd status` / `osmd agent status` / `osmd wiki status` -> `agentMarkdownStatus`
331
+ - `osmd search` -> `osMdSearch`
329
332
  - `osmd read` / `osmd agent read` / `osmd wiki read` -> `agentMarkdownFile`
330
333
  - `osmd children` / `osmd wiki children` -> `agentMarkdownChildren`
331
334
  - `osmd agent init` -> `initAgentMarkdown`
@@ -349,6 +352,8 @@ Path and permission rules:
349
352
  - Agent Wiki `append-log` supports only `log.md` and calls status first before appending.
350
353
  - The CLI uses backend GraphQL metadata directly and does not derive S3 paths, SHA paths, or backend storage conventions.
351
354
  - Atlas should inspect `path`, `source`, `access`, `owner`, `parentRef`, `exists`, `canCreate`, `canUpdate`, `canAppend`, `wikiRole`, `formatVersion`, `suggestedAction`, and `errorCode`.
355
+ - `osmd search` scopes map to backend `source` values: `os-only` -> `canonical_osmd`, `agent-overlay-only` -> `agent_overlay`, `agent-wiki-only` -> `agent_wiki`, and `combined` -> backend merged search.
356
+ - `osmd search` returns backend candidates with `path`, `source`, `access`, `owner`, `wikiRole`, `formatVersion`, `parentRef`, `exists`, `agentChildrenAllowed`, `title`, `label`, `snippet`, `rank`, `matchReason`, `toolKey`, `nodeKey`, and `nodeKind` where the backend provides them.
352
357
  - Reads never create files.
353
358
  - Create/update/append-log flows call status first and inspect `exists`, `canCreate`, `canUpdate`, `canAppend`, `suggestedAction`, and `errorCode`.
354
359
  - `create` fails when `exists` is true.
@@ -429,6 +434,44 @@ OSMD command envelopes keep the global CLI envelope and put the file metadata di
429
434
  }
430
435
  ```
431
436
 
437
+ Merged OSMD search keeps the same envelope and returns backend-ranked candidates:
438
+
439
+ ```json
440
+ {
441
+ "ok": true,
442
+ "command": "osmd.search",
443
+ "status": 200,
444
+ "data": {
445
+ "query": "Wave Tools",
446
+ "scope": "combined",
447
+ "count": 3,
448
+ "candidates": [
449
+ {
450
+ "path": "directory/Wave Tools Team/.agent/notes.md",
451
+ "source": "agent_overlay",
452
+ "access": "read_write",
453
+ "owner": "atlas",
454
+ "wikiRole": "notes",
455
+ "formatVersion": "agent_markdown_v1",
456
+ "parentRef": "directory/Wave Tools Team",
457
+ "exists": true,
458
+ "agentChildrenAllowed": false,
459
+ "title": "notes.md",
460
+ "label": "notes.md",
461
+ "snippet": "...",
462
+ "rank": 1,
463
+ "matchReason": "content",
464
+ "toolKey": "agent_overlay",
465
+ "nodeKey": "notes",
466
+ "nodeKind": "agent_overlay_file"
467
+ }
468
+ ]
469
+ },
470
+ "error": null,
471
+ "meta": { "requestId": "req_125" }
472
+ }
473
+ ```
474
+
432
475
  On write preflight errors, `data` contains the status metadata and `error.suggestedAction` mirrors backend guidance:
433
476
 
434
477
  ```json
@@ -482,6 +525,12 @@ These wrap backend-owned markdown-tree primitives:
482
525
  Discovery, ranking, canonical paths, and narrowing are backend-owned.
483
526
  An empty `find` result (`candidates: []`) means no evidence for that exact query/scope, not confirmed global absence.
484
527
  `markdownTreeFind` remains canonical-focused. Agent overlay and Agent Wiki files are discoverable through `osmd tree`, `osmd children`, and `osmd status`, not through `find`.
528
+ Use `wave osmd search "<query>" --scope combined` when Atlas needs merged canonical OSMD, `.agent`, and Agent Wiki search. Use narrower scopes for targeted memory lookup:
529
+
530
+ - `--scope os-only` searches canonical OSMD only.
531
+ - `--scope agent-overlay-only` searches entity-specific `.agent` files.
532
+ - `--scope agent-wiki-only` searches broad Agent Wiki files, including `index.md` and append-only `log.md`.
533
+ - `--scope combined` searches the backend merged OSMD surface.
485
534
 
486
535
  Ambiguity contract:
487
536
 
package/dist/index.cjs CHANGED
@@ -6143,10 +6143,17 @@ var agentMarkdownErrorCodeSchema = import_zod16.z.enum([
6143
6143
  var agentMarkdownErrorCodeFieldSchema = agentMarkdownErrorCodeSchema.nullable().catch(null);
6144
6144
  var nonEmptyString3 = import_zod16.z.string().min(1);
6145
6145
  var nonNegativeInt3 = import_zod16.z.coerce.number().int().min(0);
6146
+ var positiveInt = import_zod16.z.coerce.number().int().min(1);
6146
6147
  var supportedAgentOverlayFile = "notes.md";
6147
6148
  var supportedWikiIndexFile = "index.md";
6148
6149
  var supportedWikiLogFile = "log.md";
6149
6150
  var agentOverlayFileSchema = import_zod16.z.enum([supportedAgentOverlayFile]);
6151
+ var osmdSearchScopeSchema = import_zod16.z.enum([
6152
+ "os-only",
6153
+ "agent-overlay-only",
6154
+ "agent-wiki-only",
6155
+ "combined"
6156
+ ]);
6150
6157
  var agentMarkdownFileSchema = import_zod16.z.object({
6151
6158
  path: import_zod16.z.string(),
6152
6159
  source: sourceSchema,
@@ -6178,6 +6185,47 @@ var agentMarkdownMutationDataSchema = import_zod16.z.union([
6178
6185
  agentMarkdownFileSchema,
6179
6186
  import_zod16.z.object({ files: agentMarkdownFilesSchema })
6180
6187
  ]);
6188
+ var osmdSearchCandidateSchema = import_zod16.z.preprocess(
6189
+ normalizeAgentMarkdownJsonKeys,
6190
+ import_zod16.z.object({
6191
+ path: import_zod16.z.string(),
6192
+ source: sourceSchema,
6193
+ access: accessSchema,
6194
+ owner: ownerSchema,
6195
+ wikiRole: import_zod16.z.string().nullable().optional(),
6196
+ formatVersion: import_zod16.z.string().nullable().optional(),
6197
+ parentRef: import_zod16.z.string().nullable().optional(),
6198
+ exists: import_zod16.z.boolean(),
6199
+ agentChildrenAllowed: import_zod16.z.boolean(),
6200
+ title: import_zod16.z.string(),
6201
+ label: import_zod16.z.string(),
6202
+ snippet: import_zod16.z.string().nullable().optional(),
6203
+ rank: import_zod16.z.number().int(),
6204
+ matchReason: import_zod16.z.string().nullable().optional(),
6205
+ toolKey: import_zod16.z.string().nullable().optional(),
6206
+ nodeKey: import_zod16.z.string().nullable().optional(),
6207
+ nodeKind: import_zod16.z.string().nullable().optional()
6208
+ }).transform((value) => ({
6209
+ ...value,
6210
+ wikiRole: value.wikiRole ?? null,
6211
+ formatVersion: value.formatVersion ?? null,
6212
+ parentRef: value.parentRef ?? null,
6213
+ snippet: value.snippet ?? null,
6214
+ matchReason: value.matchReason ?? null,
6215
+ toolKey: value.toolKey ?? null,
6216
+ nodeKey: value.nodeKey ?? null,
6217
+ nodeKind: value.nodeKind ?? null
6218
+ }))
6219
+ );
6220
+ var osmdSearchResultSchema = import_zod16.z.preprocess(
6221
+ normalizeAgentMarkdownJsonKeys,
6222
+ import_zod16.z.object({
6223
+ query: import_zod16.z.string(),
6224
+ scope: import_zod16.z.string(),
6225
+ count: import_zod16.z.number().int().min(0),
6226
+ candidates: import_zod16.z.array(osmdSearchCandidateSchema)
6227
+ })
6228
+ );
6181
6229
  var mutationPayloadSchema = import_zod16.z.object({
6182
6230
  ok: import_zod16.z.boolean(),
6183
6231
  status: import_zod16.z.number(),
@@ -6229,6 +6277,30 @@ var AGENT_MARKDOWN_FILE_SELECTION = `{
6229
6277
  content
6230
6278
  url
6231
6279
  }`;
6280
+ var OSMD_SEARCH_SELECTION = `{
6281
+ query
6282
+ scope
6283
+ count
6284
+ candidates {
6285
+ path
6286
+ source
6287
+ access
6288
+ owner
6289
+ wikiRole
6290
+ formatVersion
6291
+ parentRef
6292
+ exists
6293
+ agentChildrenAllowed
6294
+ title
6295
+ label
6296
+ snippet
6297
+ rank
6298
+ matchReason
6299
+ toolKey
6300
+ nodeKey
6301
+ nodeKind
6302
+ }
6303
+ }`;
6232
6304
  var MUTATION_RESULT_SELECTION = "{ ok status errorCode data errors }";
6233
6305
  var AGENT_JSON_KEY_ALIASES = {
6234
6306
  can_create: "canCreate",
@@ -6239,7 +6311,11 @@ var AGENT_JSON_KEY_ALIASES = {
6239
6311
  parent_ref: "parentRef",
6240
6312
  agent_children_allowed: "agentChildrenAllowed",
6241
6313
  suggested_action: "suggestedAction",
6242
- error_code: "errorCode"
6314
+ error_code: "errorCode",
6315
+ match_reason: "matchReason",
6316
+ tool_key: "toolKey",
6317
+ node_key: "nodeKey",
6318
+ node_kind: "nodeKind"
6243
6319
  };
6244
6320
  function isSupportedAgentMarkdownFile(file) {
6245
6321
  if (file.source !== "agent_overlay") {
@@ -6391,6 +6467,22 @@ async function requestAgentMarkdownChildren(params) {
6391
6467
  schema: agentMarkdownFilesSchema
6392
6468
  });
6393
6469
  }
6470
+ async function requestOsmdSearch(params) {
6471
+ return requestOsmdQuery({
6472
+ command: params.command,
6473
+ operationName: "OsMdSearch",
6474
+ runtimeOptions: params.runtimeOptions,
6475
+ field: "os_md_search",
6476
+ variables: {
6477
+ organization_id: params.organizationId,
6478
+ query: params.query,
6479
+ source: backendSearchSourceForScope(params.scope),
6480
+ limit: params.limit
6481
+ },
6482
+ selectionSet: OSMD_SEARCH_SELECTION,
6483
+ schema: osmdSearchResultSchema
6484
+ });
6485
+ }
6394
6486
  async function runAgentMarkdownMutation(params) {
6395
6487
  const result = await graphqlRequest({
6396
6488
  config: getConfig(params.runtimeOptions),
@@ -6503,6 +6595,46 @@ function parseOptionalSource(value) {
6503
6595
  }
6504
6596
  return parsed.data;
6505
6597
  }
6598
+ function parseOsmdSearchScope(value) {
6599
+ const raw = typeof value === "string" && value.trim() !== "" ? value.trim() : "combined";
6600
+ const parsed = osmdSearchScopeSchema.safeParse(raw);
6601
+ if (!parsed.success) {
6602
+ throw new CliError({
6603
+ message: "Invalid OSMD search scope. Use os-only, agent-overlay-only, agent-wiki-only, or combined.",
6604
+ kind: "invalid_args",
6605
+ status: 400,
6606
+ exitCode: EXIT_CODES.invalidArgs,
6607
+ details: { supportedScopes: osmdSearchScopeSchema.options }
6608
+ });
6609
+ }
6610
+ return parsed.data;
6611
+ }
6612
+ function backendSearchSourceForScope(scope) {
6613
+ if (scope === "os-only") {
6614
+ return "canonical_osmd";
6615
+ }
6616
+ if (scope === "agent-overlay-only") {
6617
+ return "agent_overlay";
6618
+ }
6619
+ if (scope === "agent-wiki-only") {
6620
+ return "agent_wiki";
6621
+ }
6622
+ return "combined";
6623
+ }
6624
+ function parseSearchLimit(value) {
6625
+ const raw = value === void 0 || value === null || value === "" ? "10" : value;
6626
+ const parsed = positiveInt.safeParse(raw);
6627
+ if (!parsed.success) {
6628
+ throw new CliError({
6629
+ message: "Invalid OSMD search limit. Use a positive integer.",
6630
+ kind: "invalid_args",
6631
+ status: 400,
6632
+ exitCode: EXIT_CODES.invalidArgs,
6633
+ details: { issues: parsed.error.issues }
6634
+ });
6635
+ }
6636
+ return parsed.data;
6637
+ }
6506
6638
  function parseDepth(value) {
6507
6639
  if (value === void 0 || value === null || value === "") {
6508
6640
  return 1;
@@ -6792,7 +6924,7 @@ function registerOsmdCommands(program) {
6792
6924
  })
6793
6925
  });
6794
6926
  });
6795
- osmd.command("children [path]").description("List backend-supported agent markdown children; search remains canonical-only").option("--parent-ref <parentRef>", "Canonical OSMD parent ref for .agent files").option("--source <source>", "Filter by canonical_osmd, agent_overlay, or agent_wiki").action(async (path, opts, cmd) => {
6927
+ osmd.command("children [path]").description("List backend-supported agent markdown children").option("--parent-ref <parentRef>", "Canonical OSMD parent ref for .agent files").option("--source <source>", "Filter by canonical_osmd, agent_overlay, or agent_wiki").action(async (path, opts, cmd) => {
6796
6928
  const { organizationId, runtimeOptions } = await resolveOsmdContext(cmd);
6797
6929
  const result = await requestAgentMarkdownChildren({
6798
6930
  command: "osmd.children",
@@ -6811,6 +6943,25 @@ function registerOsmdCommands(program) {
6811
6943
  })
6812
6944
  });
6813
6945
  });
6946
+ osmd.command("search <query>").description("Search merged OSMD, .agent overlays, and Agent Wiki through backend OSMD search").option("--scope <scope>", "os-only, agent-overlay-only, agent-wiki-only, or combined", "combined").option("--limit <limit>", "Maximum number of results", "10").action(async (query, opts, cmd) => {
6947
+ const { organizationId, runtimeOptions } = await resolveOsmdContext(cmd);
6948
+ const result = await requestOsmdSearch({
6949
+ command: "osmd.search",
6950
+ runtimeOptions,
6951
+ organizationId,
6952
+ query: nonEmptyString3.parse(query).trim(),
6953
+ scope: parseOsmdSearchScope(opts.scope),
6954
+ limit: parseSearchLimit(opts.limit)
6955
+ });
6956
+ return printEnvelopeAndExit({
6957
+ envelope: buildSuccessEnvelope({
6958
+ command: "osmd.search",
6959
+ status: result.status,
6960
+ data: result.data,
6961
+ requestId: result.requestId
6962
+ })
6963
+ });
6964
+ });
6814
6965
  const agent = osmd.command("agent").description(".agent overlay memory attached to canonical OSMD parents; supports notes.md");
6815
6966
  agent.command("status <parent-ref> <file>").description("Show .agent notes.md metadata without creating files").action(async (parentRef, file, _opts, cmd) => {
6816
6967
  const { organizationId, runtimeOptions } = await resolveOsmdContext(cmd);
package/dist/index.js CHANGED
@@ -6142,10 +6142,17 @@ var agentMarkdownErrorCodeSchema = z16.enum([
6142
6142
  var agentMarkdownErrorCodeFieldSchema = agentMarkdownErrorCodeSchema.nullable().catch(null);
6143
6143
  var nonEmptyString3 = z16.string().min(1);
6144
6144
  var nonNegativeInt3 = z16.coerce.number().int().min(0);
6145
+ var positiveInt = z16.coerce.number().int().min(1);
6145
6146
  var supportedAgentOverlayFile = "notes.md";
6146
6147
  var supportedWikiIndexFile = "index.md";
6147
6148
  var supportedWikiLogFile = "log.md";
6148
6149
  var agentOverlayFileSchema = z16.enum([supportedAgentOverlayFile]);
6150
+ var osmdSearchScopeSchema = z16.enum([
6151
+ "os-only",
6152
+ "agent-overlay-only",
6153
+ "agent-wiki-only",
6154
+ "combined"
6155
+ ]);
6149
6156
  var agentMarkdownFileSchema = z16.object({
6150
6157
  path: z16.string(),
6151
6158
  source: sourceSchema,
@@ -6177,6 +6184,47 @@ var agentMarkdownMutationDataSchema = z16.union([
6177
6184
  agentMarkdownFileSchema,
6178
6185
  z16.object({ files: agentMarkdownFilesSchema })
6179
6186
  ]);
6187
+ var osmdSearchCandidateSchema = z16.preprocess(
6188
+ normalizeAgentMarkdownJsonKeys,
6189
+ z16.object({
6190
+ path: z16.string(),
6191
+ source: sourceSchema,
6192
+ access: accessSchema,
6193
+ owner: ownerSchema,
6194
+ wikiRole: z16.string().nullable().optional(),
6195
+ formatVersion: z16.string().nullable().optional(),
6196
+ parentRef: z16.string().nullable().optional(),
6197
+ exists: z16.boolean(),
6198
+ agentChildrenAllowed: z16.boolean(),
6199
+ title: z16.string(),
6200
+ label: z16.string(),
6201
+ snippet: z16.string().nullable().optional(),
6202
+ rank: z16.number().int(),
6203
+ matchReason: z16.string().nullable().optional(),
6204
+ toolKey: z16.string().nullable().optional(),
6205
+ nodeKey: z16.string().nullable().optional(),
6206
+ nodeKind: z16.string().nullable().optional()
6207
+ }).transform((value) => ({
6208
+ ...value,
6209
+ wikiRole: value.wikiRole ?? null,
6210
+ formatVersion: value.formatVersion ?? null,
6211
+ parentRef: value.parentRef ?? null,
6212
+ snippet: value.snippet ?? null,
6213
+ matchReason: value.matchReason ?? null,
6214
+ toolKey: value.toolKey ?? null,
6215
+ nodeKey: value.nodeKey ?? null,
6216
+ nodeKind: value.nodeKind ?? null
6217
+ }))
6218
+ );
6219
+ var osmdSearchResultSchema = z16.preprocess(
6220
+ normalizeAgentMarkdownJsonKeys,
6221
+ z16.object({
6222
+ query: z16.string(),
6223
+ scope: z16.string(),
6224
+ count: z16.number().int().min(0),
6225
+ candidates: z16.array(osmdSearchCandidateSchema)
6226
+ })
6227
+ );
6180
6228
  var mutationPayloadSchema = z16.object({
6181
6229
  ok: z16.boolean(),
6182
6230
  status: z16.number(),
@@ -6228,6 +6276,30 @@ var AGENT_MARKDOWN_FILE_SELECTION = `{
6228
6276
  content
6229
6277
  url
6230
6278
  }`;
6279
+ var OSMD_SEARCH_SELECTION = `{
6280
+ query
6281
+ scope
6282
+ count
6283
+ candidates {
6284
+ path
6285
+ source
6286
+ access
6287
+ owner
6288
+ wikiRole
6289
+ formatVersion
6290
+ parentRef
6291
+ exists
6292
+ agentChildrenAllowed
6293
+ title
6294
+ label
6295
+ snippet
6296
+ rank
6297
+ matchReason
6298
+ toolKey
6299
+ nodeKey
6300
+ nodeKind
6301
+ }
6302
+ }`;
6231
6303
  var MUTATION_RESULT_SELECTION = "{ ok status errorCode data errors }";
6232
6304
  var AGENT_JSON_KEY_ALIASES = {
6233
6305
  can_create: "canCreate",
@@ -6238,7 +6310,11 @@ var AGENT_JSON_KEY_ALIASES = {
6238
6310
  parent_ref: "parentRef",
6239
6311
  agent_children_allowed: "agentChildrenAllowed",
6240
6312
  suggested_action: "suggestedAction",
6241
- error_code: "errorCode"
6313
+ error_code: "errorCode",
6314
+ match_reason: "matchReason",
6315
+ tool_key: "toolKey",
6316
+ node_key: "nodeKey",
6317
+ node_kind: "nodeKind"
6242
6318
  };
6243
6319
  function isSupportedAgentMarkdownFile(file) {
6244
6320
  if (file.source !== "agent_overlay") {
@@ -6390,6 +6466,22 @@ async function requestAgentMarkdownChildren(params) {
6390
6466
  schema: agentMarkdownFilesSchema
6391
6467
  });
6392
6468
  }
6469
+ async function requestOsmdSearch(params) {
6470
+ return requestOsmdQuery({
6471
+ command: params.command,
6472
+ operationName: "OsMdSearch",
6473
+ runtimeOptions: params.runtimeOptions,
6474
+ field: "os_md_search",
6475
+ variables: {
6476
+ organization_id: params.organizationId,
6477
+ query: params.query,
6478
+ source: backendSearchSourceForScope(params.scope),
6479
+ limit: params.limit
6480
+ },
6481
+ selectionSet: OSMD_SEARCH_SELECTION,
6482
+ schema: osmdSearchResultSchema
6483
+ });
6484
+ }
6393
6485
  async function runAgentMarkdownMutation(params) {
6394
6486
  const result = await graphqlRequest({
6395
6487
  config: getConfig(params.runtimeOptions),
@@ -6502,6 +6594,46 @@ function parseOptionalSource(value) {
6502
6594
  }
6503
6595
  return parsed.data;
6504
6596
  }
6597
+ function parseOsmdSearchScope(value) {
6598
+ const raw = typeof value === "string" && value.trim() !== "" ? value.trim() : "combined";
6599
+ const parsed = osmdSearchScopeSchema.safeParse(raw);
6600
+ if (!parsed.success) {
6601
+ throw new CliError({
6602
+ message: "Invalid OSMD search scope. Use os-only, agent-overlay-only, agent-wiki-only, or combined.",
6603
+ kind: "invalid_args",
6604
+ status: 400,
6605
+ exitCode: EXIT_CODES.invalidArgs,
6606
+ details: { supportedScopes: osmdSearchScopeSchema.options }
6607
+ });
6608
+ }
6609
+ return parsed.data;
6610
+ }
6611
+ function backendSearchSourceForScope(scope) {
6612
+ if (scope === "os-only") {
6613
+ return "canonical_osmd";
6614
+ }
6615
+ if (scope === "agent-overlay-only") {
6616
+ return "agent_overlay";
6617
+ }
6618
+ if (scope === "agent-wiki-only") {
6619
+ return "agent_wiki";
6620
+ }
6621
+ return "combined";
6622
+ }
6623
+ function parseSearchLimit(value) {
6624
+ const raw = value === void 0 || value === null || value === "" ? "10" : value;
6625
+ const parsed = positiveInt.safeParse(raw);
6626
+ if (!parsed.success) {
6627
+ throw new CliError({
6628
+ message: "Invalid OSMD search limit. Use a positive integer.",
6629
+ kind: "invalid_args",
6630
+ status: 400,
6631
+ exitCode: EXIT_CODES.invalidArgs,
6632
+ details: { issues: parsed.error.issues }
6633
+ });
6634
+ }
6635
+ return parsed.data;
6636
+ }
6505
6637
  function parseDepth(value) {
6506
6638
  if (value === void 0 || value === null || value === "") {
6507
6639
  return 1;
@@ -6791,7 +6923,7 @@ function registerOsmdCommands(program) {
6791
6923
  })
6792
6924
  });
6793
6925
  });
6794
- osmd.command("children [path]").description("List backend-supported agent markdown children; search remains canonical-only").option("--parent-ref <parentRef>", "Canonical OSMD parent ref for .agent files").option("--source <source>", "Filter by canonical_osmd, agent_overlay, or agent_wiki").action(async (path, opts, cmd) => {
6926
+ osmd.command("children [path]").description("List backend-supported agent markdown children").option("--parent-ref <parentRef>", "Canonical OSMD parent ref for .agent files").option("--source <source>", "Filter by canonical_osmd, agent_overlay, or agent_wiki").action(async (path, opts, cmd) => {
6795
6927
  const { organizationId, runtimeOptions } = await resolveOsmdContext(cmd);
6796
6928
  const result = await requestAgentMarkdownChildren({
6797
6929
  command: "osmd.children",
@@ -6810,6 +6942,25 @@ function registerOsmdCommands(program) {
6810
6942
  })
6811
6943
  });
6812
6944
  });
6945
+ osmd.command("search <query>").description("Search merged OSMD, .agent overlays, and Agent Wiki through backend OSMD search").option("--scope <scope>", "os-only, agent-overlay-only, agent-wiki-only, or combined", "combined").option("--limit <limit>", "Maximum number of results", "10").action(async (query, opts, cmd) => {
6946
+ const { organizationId, runtimeOptions } = await resolveOsmdContext(cmd);
6947
+ const result = await requestOsmdSearch({
6948
+ command: "osmd.search",
6949
+ runtimeOptions,
6950
+ organizationId,
6951
+ query: nonEmptyString3.parse(query).trim(),
6952
+ scope: parseOsmdSearchScope(opts.scope),
6953
+ limit: parseSearchLimit(opts.limit)
6954
+ });
6955
+ return printEnvelopeAndExit({
6956
+ envelope: buildSuccessEnvelope({
6957
+ command: "osmd.search",
6958
+ status: result.status,
6959
+ data: result.data,
6960
+ requestId: result.requestId
6961
+ })
6962
+ });
6963
+ });
6813
6964
  const agent = osmd.command("agent").description(".agent overlay memory attached to canonical OSMD parents; supports notes.md");
6814
6965
  agent.command("status <parent-ref> <file>").description("Show .agent notes.md metadata without creating files").action(async (parentRef, file, _opts, cmd) => {
6815
6966
  const { organizationId, runtimeOptions } = await resolveOsmdContext(cmd);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ted-galago/wave-cli",
3
- "version": "0.1.19",
3
+ "version": "0.1.20",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "wave": "dist/index.js"
@@ -1392,6 +1392,125 @@ function runOsmdLiveVerification() {
1392
1392
  reason: "agent_overlay_update"
1393
1393
  });
1394
1394
 
1395
+ const searchCandidates = (result) => firstArrayValue(result.parsed, [["data", "candidates"]]);
1396
+ const hasOwn = (candidate, key) => Object.prototype.hasOwnProperty.call(candidate ?? {}, key);
1397
+ const hasSearchMetadata = (candidate, expectedSource) =>
1398
+ candidate &&
1399
+ typeof candidate.path === "string" &&
1400
+ candidate.source === expectedSource &&
1401
+ typeof candidate.access === "string" &&
1402
+ typeof candidate.owner === "string" &&
1403
+ hasOwn(candidate, "wikiRole") &&
1404
+ hasOwn(candidate, "formatVersion") &&
1405
+ hasOwn(candidate, "parentRef") &&
1406
+ typeof candidate.exists === "boolean";
1407
+
1408
+ const canonicalSearch = runWave(["osmd", "search", "Wave Tools", "--scope", "os-only", "--limit", "5"], env);
1409
+ results.push(canonicalSearch);
1410
+ const canonicalSearchCandidates = searchCandidates(canonicalSearch);
1411
+ osmdVerificationFailures += recordExactCheck({
1412
+ lines: osmdVerificationLines,
1413
+ label: "osmd.search canonical results include OS metadata",
1414
+ result: canonicalSearch,
1415
+ ok:
1416
+ canonicalSearch.parsed?.ok === true &&
1417
+ canonicalSearch.parsed?.command === "osmd.search" &&
1418
+ typeof canonicalSearch.parsed?.meta?.requestId === "string" &&
1419
+ canonicalSearch.parsed?.data?.scope === "canonical_osmd" &&
1420
+ canonicalSearchCandidates.some(
1421
+ (candidate) =>
1422
+ hasSearchMetadata(candidate, "canonical_osmd") &&
1423
+ candidate.access === "read_only" &&
1424
+ candidate.owner === "system"
1425
+ ),
1426
+ reason: "osmd_search_canonical"
1427
+ });
1428
+
1429
+ const wikiSearch = runWave(["osmd", "search", "Agent Wiki", "--scope", "agent-wiki-only", "--limit", "10"], env);
1430
+ results.push(wikiSearch);
1431
+ const wikiSearchCandidates = searchCandidates(wikiSearch);
1432
+ osmdVerificationFailures += recordExactCheck({
1433
+ lines: osmdVerificationLines,
1434
+ label: "osmd.search Agent Wiki results include index and log metadata",
1435
+ result: wikiSearch,
1436
+ ok:
1437
+ wikiSearch.parsed?.ok === true &&
1438
+ wikiSearch.parsed?.data?.scope === "agent_wiki" &&
1439
+ wikiSearchCandidates.some(
1440
+ (candidate) =>
1441
+ hasSearchMetadata(candidate, "agent_wiki") &&
1442
+ candidate.path === "Agent Wiki/index.md" &&
1443
+ candidate.wikiRole === "index"
1444
+ ) &&
1445
+ wikiSearchCandidates.some(
1446
+ (candidate) =>
1447
+ hasSearchMetadata(candidate, "agent_wiki") &&
1448
+ candidate.path === "Agent Wiki/log.md" &&
1449
+ candidate.wikiRole === "log" &&
1450
+ candidate.access === "append_only"
1451
+ ),
1452
+ reason: "osmd_search_agent_wiki"
1453
+ });
1454
+
1455
+ const logSearch = runWave(
1456
+ ["osmd", "search", `CLI live verify log ${verifyStamp}`, "--scope", "agent-wiki-only", "--limit", "5"],
1457
+ env
1458
+ );
1459
+ results.push(logSearch);
1460
+ const logSearchCandidates = searchCandidates(logSearch);
1461
+ osmdVerificationFailures += recordExactCheck({
1462
+ lines: osmdVerificationLines,
1463
+ label: "osmd.search Agent Wiki log content result",
1464
+ result: logSearch,
1465
+ ok:
1466
+ logSearch.parsed?.ok === true &&
1467
+ logSearchCandidates.some(
1468
+ (candidate) =>
1469
+ hasSearchMetadata(candidate, "agent_wiki") &&
1470
+ candidate.path === "Agent Wiki/log.md" &&
1471
+ candidate.wikiRole === "log"
1472
+ ),
1473
+ reason: "osmd_search_agent_wiki_log"
1474
+ });
1475
+
1476
+ const notesSearch = runWave(
1477
+ ["osmd", "search", notesContent, "--scope", "agent-overlay-only", "--limit", "5"],
1478
+ env
1479
+ );
1480
+ results.push(notesSearch);
1481
+ const notesSearchCandidates = searchCandidates(notesSearch);
1482
+ osmdVerificationFailures += recordExactCheck({
1483
+ lines: osmdVerificationLines,
1484
+ label: "osmd.search agent overlay notes content result",
1485
+ result: notesSearch,
1486
+ ok:
1487
+ notesSearch.parsed?.ok === true &&
1488
+ notesSearch.parsed?.data?.scope === "agent_overlay" &&
1489
+ notesSearchCandidates.some(
1490
+ (candidate) =>
1491
+ hasSearchMetadata(candidate, "agent_overlay") &&
1492
+ candidate.path.endsWith("/.agent/notes.md") &&
1493
+ candidate.wikiRole === "notes" &&
1494
+ candidate.parentRef === parentRef
1495
+ ),
1496
+ reason: "osmd_search_agent_overlay_notes"
1497
+ });
1498
+
1499
+ const combinedSearch = runWave(["osmd", "search", "Wave", "--scope", "combined", "--limit", "3"], env);
1500
+ results.push(combinedSearch);
1501
+ osmdVerificationFailures += recordExactCheck({
1502
+ lines: osmdVerificationLines,
1503
+ label: "osmd.search combined scope returns stable envelope",
1504
+ result: combinedSearch,
1505
+ ok:
1506
+ combinedSearch.parsed?.ok === true &&
1507
+ combinedSearch.parsed?.command === "osmd.search" &&
1508
+ combinedSearch.parsed?.data?.scope === "combined" &&
1509
+ Array.isArray(combinedSearch.parsed?.data?.candidates) &&
1510
+ typeof combinedSearch.parsed?.meta?.requestId === "string",
1511
+ reason: "osmd_search_combined"
1512
+ });
1513
+
1395
1514
  }
1396
1515
 
1397
1516
  runOsmdLiveVerification();