node-autotask 0.37.1 → 0.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/MCP_TOOL_CATALOG.json +127 -44
  3. package/MCP_TOOL_MANIFEST.md +9 -9
  4. package/N8N_MCP_MANIFEST.json +4 -4
  5. package/N8N_MCP_MANIFEST.md +5 -5
  6. package/README.md +3 -0
  7. package/capabilities.json +2500 -1713
  8. package/capabilities.schema.json +2 -1
  9. package/dist/capabilities.cjs +2 -2
  10. package/dist/capabilities.d.cts +4 -4
  11. package/dist/capabilities.d.ts +4 -4
  12. package/dist/capabilities.js +1 -1
  13. package/dist/{chunk-KQ6HMBB4.js → chunk-2KQS3RHQ.js} +2499 -1712
  14. package/dist/{chunk-TBFXRNNE.cjs → chunk-45PLS73K.cjs} +2452 -2065
  15. package/dist/chunk-5VHSLJMR.js +71 -0
  16. package/dist/{chunk-PFFW4DIK.cjs → chunk-6ROB5KXB.cjs} +285 -285
  17. package/dist/{chunk-7IADHNBZ.js → chunk-FV5PJLIZ.js} +2602 -2215
  18. package/dist/{chunk-25VGFT5M.cjs → chunk-KSNK6UEW.cjs} +143 -143
  19. package/dist/{chunk-PFJAMFUL.js → chunk-LD5UPSDB.js} +2 -2
  20. package/dist/chunk-MJTKK3QG.cjs +71 -0
  21. package/dist/{chunk-7WI7FBPB.js → chunk-OKFTECIE.js} +2 -2
  22. package/dist/{chunk-HBYKTXN3.cjs → chunk-RAZEXOLC.cjs} +2499 -1712
  23. package/dist/{index-m-7fOwFl.d.cts → index-BQVStxwi.d.cts} +15 -1
  24. package/dist/{index-m-7fOwFl.d.ts → index-BQVStxwi.d.ts} +15 -1
  25. package/dist/{index-CqepIQfp.d.cts → index-BVOOHPvr.d.cts} +28 -8
  26. package/dist/{index-BDqw377y.d.ts → index-Bmoiwhx2.d.ts} +28 -8
  27. package/dist/index.cjs +27 -22
  28. package/dist/index.d.cts +26 -5
  29. package/dist/index.d.ts +26 -5
  30. package/dist/index.js +9 -4
  31. package/dist/operations/index.cjs +249 -227
  32. package/dist/operations/index.d.cts +76 -15
  33. package/dist/operations/index.d.ts +76 -15
  34. package/dist/operations/index.js +60 -38
  35. package/dist/pool.cjs +10 -9
  36. package/dist/pool.d.cts +2 -2
  37. package/dist/pool.d.ts +2 -2
  38. package/dist/pool.js +5 -4
  39. package/dist/resources/index.cjs +5 -4
  40. package/dist/resources/index.d.cts +2 -2
  41. package/dist/resources/index.d.ts +2 -2
  42. package/dist/resources/index.js +4 -3
  43. package/dist/types/index.d.cts +1 -1
  44. package/dist/types/index.d.ts +1 -1
  45. package/dist/untrusted.cjs +24 -70
  46. package/dist/untrusted.js +12 -58
  47. package/docs/API.md +129 -3
  48. package/examples/mcp/manifest.ts +5 -0
  49. package/examples/mcp/rank.ts +62 -0
  50. package/examples/mcp/tools-meta.ts +6 -1
  51. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -5,6 +5,37 @@ All notable changes to this project are documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.39.0] - Unreleased
9
+
10
+ Minor: the plan hash moves `2dab3980...` (0.38.0) -> `9bb87de7bcbda60f6c44955dba52b8e61e9c5547750ea8acacfcb6f261d7734f` (a new `field-semantics` caveat on `time_entries.query` / `time_entries.get`), so the MCP server must re-pin.
11
+
12
+ ### Changed
13
+ - **#282: label siblings are never missing for a keyed field.** When a labelled field is present in a query row, aggregate group key or fetched record, its sibling is now always there: `<fk>Name` (`contractIDName`, `assignedResourceIDName`, ...) and the deprecated `assignedResourceName` alias are `null` when the id is null, 0 or unresolved, and `<picklist>Label` (`statusLabel`) is `null` when the value is null. Previously these keys were omitted, which broke clients that read them unconditionally. Non-null values are unchanged; `*Name` values keep the 200-char cap and the `<untrusted_content>` wrapping. The `assignedResourceName` alias stays in 0.39.0 (its removal, announced for this minor, is deferred).
14
+ ### Added
15
+ - **#282: `operations.fieldCatalog` compact rows and a size cap.** Measured live from the SDK (no client in between): a `tickets` result is 19,816 bytes full, 137,355 bytes with `labels: true` (what the MCP server sends for a one-resource call) and 11,057 bytes with `compact: true`; `time_entries` is 9,218 / 11,339 / 5,320 bytes. So the >96 KB payload clients saw cut off is the SDK's own full labelled result.
16
+ - `compact: true` serves each field row as `{ name, type, isPickList, isReference, udf }`. Picklist values ride a compact row only with `labels: true` and a `fields` filter. The row name lists (`required`, `readOnly`, `queryable`, `picklistFields`) are kept.
17
+ - `maxBytes` (integer >= 4096) caps the UTF-8 JSON size. Over it, field rows are dropped from the end (udf rows first, then fields rows, last resource first; the name lists only if the field rows alone cannot fit), and the result carries `truncated: true` plus `truncation: { reason: 'maxBytes', maxBytes, fullBytes, omitted: [{ resource, kind, count }], note }`. The result is always valid JSON and never over the cap: when the envelope alone cannot fit (many resources under a small cap), the call is refused with `CONFIG_ERROR`. The cost is linear in the result size: each dropped entry is measured once.
18
+ - Defaults are unchanged (full rows, no cap), so existing SDK callers see the same output. The SDK cannot tell an MCP caller apart, and the server's describe enrichment reads the full rows, so the compact default belongs in the server: pass `compact: true` (and a `maxBytes`) on model-facing calls.
19
+ - Types: `FieldCatalogResult` / `FieldCatalogRow` take the field-row type as a parameter (default the full row; `fieldCatalog(client, { compact: true })` is typed with `FieldCatalogCompactFieldRow`). `FieldCatalogResult.truncated` is now `boolean` (was the literal `false`); over-cap wire requests are still refused, never truncated. New exports: `FieldCatalogCompactFieldRow`, `FieldCatalogTruncation`, `FieldCatalogTrimKind`, `MIN_FIELD_CATALOG_MAX_BYTES`.
20
+ - **#282: `hoursWorked` vs `hoursToBill` in the registry.** `time_entries.query` and `time_entries.get` carry a `field-semantics` caveat (a new caveat kind, `fields` required) whose note a server can quote: `hoursWorked` is the time worked (effort, utilisation); `hoursToBill` is the vendor-derived billing quantity (read-only: `hoursWorked` plus `offsetHours`, rounded to two decimals), stays populated on `isNonBillable` entries, and can differ from `hoursWorked` on the same entry.
21
+
22
+ ## [0.38.0] - Unreleased
23
+
24
+ Minor: query/aggregate/count answer "company X time in a window, with labels" in 1-3 calls using existing operations. The plan hash changes (registry text), so the MCP server must re-pin.
25
+
26
+ ### Added
27
+ - **#274: `in` / `notIn` accept a comma-separated string.** `value: "1,2,3"` is split on commas, trimmed, empty tokens dropped, and canonical number tokens become numbers (`"007"` stays a string; `udf: true` values stay strings), producing the same wire filter as `[1, 2, 3]`. Applies everywhere filters are built (query, count, aggregate, latest walks, the field-name pre-check). A string with no tokens is refused pre-request with `AutotaskConfigError`. Array values are unchanged. Filter grammar text in the registry, README and `docs/API.md` updated.
28
+ - **#275: relation filters.** On a resource with a `ticketID` / `taskID` / `projectID` foreign key, a condition on `ticket.<field>`, `task.<field>` or `project.<field>` is resolved to `<relation>ID in [ids]` (one parent read of at most 300 ids per relation; per leaf inside an `or`). Works in `queryBounded` / the invoke `query` op, `count` and `operations.aggregate`, so `time_entries` can be scoped by company: `[{ field: 'ticket.companyID', op: 'eq', value: 123 }, { field: 'dateWorked', op: 'gte', value: '2026-10-01' }]`. No parent match returns an empty result (`relationNote`, `count` 0) without the child call; more than 300 parents is a typed `AutotaskConfigError`; relation field names are checked against the parent's field set pre-request. New additive result field `BoundedQueryResult.relationNote` / `AggregateResult.relationNote`. `companies.unbilledWork` now uses the shared join-set helper (`capJoinSet`, cap 300), no behaviour change.
29
+ - **#276: default label siblings on query, aggregate and fetch.** The invoke `<resource>.query` rows, `operations.aggregate` group keys and `operations.fetchMany` / `fetchByIds` records now carry `<picklist>Label` (e.g. `statusLabel`) and `<fk>Name` siblings (`companyIDName`, `contractIDName`, `ticketIDName` = "<number> <title>", `roleIDName`, `billingCodeIDName`, and `resourceIDName` / `assignedResourceIDName` / every `*ResourceIDName`) through `resolveCompositeNames` (now also resolving companies and tickets, and any resource's picklists). Default on; `names: false` opts out per call (new key on the query bag, aggregate opts and fetch opts). Cold reads stay capped at 20 per call: capped ids get a null name and the result carries `names: { truncated, capped, note, reasons? }`. Warm caches cost zero vendor calls. `*Name` values are vendor free text, so they are capped at 200 chars (noteChars marker) and wrapped in `<untrusted_content>` markers by the SDK; picklist `*Label` values stay raw. `assignedResourceName` is written as a deprecated alias of `assignedResourceIDName` for this minor release. Worst-case row growth (full model, every FK set): tickets ~50%, time_entries ~77% (see `docs/API.md` §11.27). Behaviour change: callers that compare whole rows should pass `names: false`.
30
+ - **#277: catalog discoverability.** `MCP_TOOL_CATALOG.json` rows for the repeated date-window helpers (`today`, `yesterday`, `last24h`, `last7/14/30/90`, `lastFullWeek/Fortnight/Month/Quarter`, `customRange` on `time_entries`, `billing_items`, `invoices`, plus `time_entries.dateWorkedWindow`: 37 rows) carry `hidden: true` + `hiddenReason`; they stay in the catalog and callable by exact key. `operations.aggregate`'s purpose gains discovery text (totals, sums, counts, hours per ticket / resource / company / contract / month). The `autotask_catalog` meta-tool data documents `q` and `includeHidden`, and the reference server (`examples/mcp/rank.ts`) ships the ranker: BM25 x squared query-term coverage, rows under half the terms dropped, tool-served rows x1.5, hidden rows excluded unless asked, exact key always resolves. Golden test: "aggregate time entries hours grouped by ticket resource" ranks `operations.aggregate` first (7 rows, previously 518 `time_entries.*` rows without aggregate in the top 20).
31
+ ### Deprecated
32
+ - **#278: `time_entries.recentTickets`** (removed in the next minor; works unchanged until then). It is a subset of `operations.aggregate('time_entries.query', [resourceID eq R, dateWorked window, optional ticket.companyID eq C], { groupBy: ['ticketID'], sum: ['hoursWorked'] })`, whose group keys now carry `ticketIDName`. The registry purpose / preferredWhen (what describe shows) open with the deprecation and the replacement call, the generated method carries `@deprecated`, the catalog row carries `deprecated: true`, and `docs/API.md` has the worked example.
33
+ ### Changed
34
+ - Label siblings are on by default (#276): code that compares whole query / fetch rows or aggregate keys should pass `names: false`.
35
+ ### Fixed
36
+ - **#280: `operations.aggregate` checks filter field names.** Filter, `groupBy` and `sum` names now go through the same field-name check as the invoke query/count bags (one shared `findUnknownFieldNames`), against the vendored spec plus the plan-pinned live-only fields. An unknown name is a typed `CONFIG_ERROR` in the one-round problem list, with no vendor request (no metadata read either). `udf: true` conditions are exempt; relation leaves (`ticket.<field>`) are checked against the parent's field set by the relation rewrite. A bucketed `groupBy` entry with an unknown base is quoted as given (`"nope@year": "nope"`).
37
+ - **#281: the `query()` iterator resolves relation filters and labels rows.** `client.<resource>.query()` (the iterator behind the MCP server's `output_path`) now runs the same relation rewrite as `queryBounded` / `count` (`ticket.<field>` etc. become `<relation>ID in [ids]`; no parent match yields nothing with no child call; more than 300 parents is the typed error), and adds the default label siblings per page through the same `labelRows` (new `QueryParams.names`, `false` opts out; the cold-read cap of 20 applies per page and capped ids get a null `*Name`, since an iterator has no `names` summary). `queryAll` also resolves relation filters (raw rows, no labels). As a backstop, `HttpClient.request` refuses any `/query` call whose filter still carries a dotted non-UDF field, so no path can send an unresolved relation filter to the vendor. `operations.revenueRollup`'s internal walks pass `names: false` (no change to its vendor-call budget).
38
+
8
39
  ## [0.37.1] - 2026-10-29
9
40
  Patch: circuit-breaker probe-settlement fixes only; the plan hash is unchanged (`5cd6c667...`), so consumers need no re-pin for the plan.
10
41
  ### Fixed
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "generatedBy": "scripts/build-tool-catalog.mjs",
3
- "generatedAt": "2026-10-28T12:58:12.762Z",
4
- "planHash": "5cd6c6679384651e7f67a0135915bcc031ef542640d9ebb6992b729ca42efe37",
3
+ "generatedAt": "2026-10-29T10:47:35.516Z",
4
+ "planHash": "9bb87de7bcbda60f6c44955dba52b8e61e9c5547750ea8acacfcb6f261d7734f",
5
5
  "metaTools": [
6
6
  {
7
7
  "name": "autotask_catalog",
8
8
  "title": "Discover Operations (Catalog)",
9
- "description": "List the operations the SDK implements with tool/effect/dry-run/confirmation/required-args rows; bounded (limit default 40, max 500, tier + effect filters); the tool list on the server is a SUBSET — this is how a capability without a tool of its own is found. The argument set is CLOSED at the top level: an unknown argument is refused before any request, with a typed error naming the key and the valid keys.",
9
+ "description": "List the operations the SDK implements with tool/effect/dry-run/confirmation/required-args rows; bounded (limit default 40, max 500, tier + effect filters); the tool list on the server is a SUBSET — this is how a capability without a tool of its own is found. Rows flagged hidden (the repeated date-window helpers) are left out of default results and stay callable by exact key. The argument set is CLOSED at the top level: an unknown argument is refused before any request, with a typed error naming the key and the valid keys.",
10
10
  "input": {
11
11
  "limit": {
12
12
  "type": "number",
@@ -18,6 +18,14 @@
18
18
  },
19
19
  "effect": {
20
20
  "type": "read | write | destructive"
21
+ },
22
+ "q": {
23
+ "type": "string",
24
+ "note": "ranked search (most query words matched, tool-served rows first)"
25
+ },
26
+ "includeHidden": {
27
+ "type": "boolean",
28
+ "default": false
21
29
  }
22
30
  },
23
31
  "annotations": {
@@ -664,7 +672,9 @@
664
672
  "reachable": true,
665
673
  "reach": "dedicated tool",
666
674
  "reachReason": null,
667
- "boundedAlternative": null
675
+ "boundedAlternative": null,
676
+ "hidden": true,
677
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
668
678
  },
669
679
  {
670
680
  "operation": "billing_items.get",
@@ -751,7 +761,9 @@
751
761
  "reachable": true,
752
762
  "reach": "dedicated tool",
753
763
  "reachReason": null,
754
- "boundedAlternative": null
764
+ "boundedAlternative": null,
765
+ "hidden": true,
766
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
755
767
  },
756
768
  {
757
769
  "operation": "billing_items.last24h",
@@ -768,7 +780,9 @@
768
780
  "reachable": true,
769
781
  "reach": "dedicated tool",
770
782
  "reachReason": null,
771
- "boundedAlternative": null
783
+ "boundedAlternative": null,
784
+ "hidden": true,
785
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
772
786
  },
773
787
  {
774
788
  "operation": "billing_items.last30",
@@ -785,7 +799,9 @@
785
799
  "reachable": true,
786
800
  "reach": "dedicated tool",
787
801
  "reachReason": null,
788
- "boundedAlternative": null
802
+ "boundedAlternative": null,
803
+ "hidden": true,
804
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
789
805
  },
790
806
  {
791
807
  "operation": "billing_items.last7",
@@ -802,7 +818,9 @@
802
818
  "reachable": true,
803
819
  "reach": "dedicated tool",
804
820
  "reachReason": null,
805
- "boundedAlternative": null
821
+ "boundedAlternative": null,
822
+ "hidden": true,
823
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
806
824
  },
807
825
  {
808
826
  "operation": "billing_items.last90",
@@ -819,7 +837,9 @@
819
837
  "reachable": true,
820
838
  "reach": "dedicated tool",
821
839
  "reachReason": null,
822
- "boundedAlternative": null
840
+ "boundedAlternative": null,
841
+ "hidden": true,
842
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
823
843
  },
824
844
  {
825
845
  "operation": "billing_items.lastFullFortnight",
@@ -836,7 +856,9 @@
836
856
  "reachable": true,
837
857
  "reach": "dedicated tool",
838
858
  "reachReason": null,
839
- "boundedAlternative": null
859
+ "boundedAlternative": null,
860
+ "hidden": true,
861
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
840
862
  },
841
863
  {
842
864
  "operation": "billing_items.lastFullMonth",
@@ -853,7 +875,9 @@
853
875
  "reachable": true,
854
876
  "reach": "dedicated tool",
855
877
  "reachReason": null,
856
- "boundedAlternative": null
878
+ "boundedAlternative": null,
879
+ "hidden": true,
880
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
857
881
  },
858
882
  {
859
883
  "operation": "billing_items.lastFullQuarter",
@@ -870,7 +894,9 @@
870
894
  "reachable": true,
871
895
  "reach": "dedicated tool",
872
896
  "reachReason": null,
873
- "boundedAlternative": null
897
+ "boundedAlternative": null,
898
+ "hidden": true,
899
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
874
900
  },
875
901
  {
876
902
  "operation": "billing_items.lastFullWeek",
@@ -887,7 +913,9 @@
887
913
  "reachable": true,
888
914
  "reach": "dedicated tool",
889
915
  "reachReason": null,
890
- "boundedAlternative": null
916
+ "boundedAlternative": null,
917
+ "hidden": true,
918
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
891
919
  },
892
920
  {
893
921
  "operation": "billing_items.query",
@@ -940,7 +968,9 @@
940
968
  "reachable": true,
941
969
  "reach": "dedicated tool",
942
970
  "reachReason": null,
943
- "boundedAlternative": null
971
+ "boundedAlternative": null,
972
+ "hidden": true,
973
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
944
974
  },
945
975
  {
946
976
  "operation": "billing_items.update",
@@ -977,7 +1007,9 @@
977
1007
  "reachable": true,
978
1008
  "reach": "dedicated tool",
979
1009
  "reachReason": null,
980
- "boundedAlternative": null
1010
+ "boundedAlternative": null,
1011
+ "hidden": true,
1012
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
981
1013
  },
982
1014
  {
983
1015
  "operation": "change_request_links.count",
@@ -11519,7 +11551,9 @@
11519
11551
  "reachable": true,
11520
11552
  "reach": "dedicated tool",
11521
11553
  "reachReason": null,
11522
- "boundedAlternative": null
11554
+ "boundedAlternative": null,
11555
+ "hidden": true,
11556
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
11523
11557
  },
11524
11558
  {
11525
11559
  "operation": "time_entries.dateWorkedWindow",
@@ -11539,7 +11573,9 @@
11539
11573
  "reachable": true,
11540
11574
  "reach": "dedicated tool",
11541
11575
  "reachReason": null,
11542
- "boundedAlternative": null
11576
+ "boundedAlternative": null,
11577
+ "hidden": true,
11578
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
11543
11579
  },
11544
11580
  {
11545
11581
  "operation": "time_entries.delete",
@@ -11679,7 +11715,9 @@
11679
11715
  "reachable": true,
11680
11716
  "reach": "dedicated tool",
11681
11717
  "reachReason": null,
11682
- "boundedAlternative": null
11718
+ "boundedAlternative": null,
11719
+ "hidden": true,
11720
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
11683
11721
  },
11684
11722
  {
11685
11723
  "operation": "time_entries.last24h",
@@ -11696,7 +11734,9 @@
11696
11734
  "reachable": true,
11697
11735
  "reach": "dedicated tool",
11698
11736
  "reachReason": null,
11699
- "boundedAlternative": null
11737
+ "boundedAlternative": null,
11738
+ "hidden": true,
11739
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
11700
11740
  },
11701
11741
  {
11702
11742
  "operation": "time_entries.last30",
@@ -11713,7 +11753,9 @@
11713
11753
  "reachable": true,
11714
11754
  "reach": "dedicated tool",
11715
11755
  "reachReason": null,
11716
- "boundedAlternative": null
11756
+ "boundedAlternative": null,
11757
+ "hidden": true,
11758
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
11717
11759
  },
11718
11760
  {
11719
11761
  "operation": "time_entries.last7",
@@ -11730,7 +11772,9 @@
11730
11772
  "reachable": true,
11731
11773
  "reach": "dedicated tool",
11732
11774
  "reachReason": null,
11733
- "boundedAlternative": null
11775
+ "boundedAlternative": null,
11776
+ "hidden": true,
11777
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
11734
11778
  },
11735
11779
  {
11736
11780
  "operation": "time_entries.last90",
@@ -11747,7 +11791,9 @@
11747
11791
  "reachable": true,
11748
11792
  "reach": "dedicated tool",
11749
11793
  "reachReason": null,
11750
- "boundedAlternative": null
11794
+ "boundedAlternative": null,
11795
+ "hidden": true,
11796
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
11751
11797
  },
11752
11798
  {
11753
11799
  "operation": "time_entries.lastFullFortnight",
@@ -11764,7 +11810,9 @@
11764
11810
  "reachable": true,
11765
11811
  "reach": "dedicated tool",
11766
11812
  "reachReason": null,
11767
- "boundedAlternative": null
11813
+ "boundedAlternative": null,
11814
+ "hidden": true,
11815
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
11768
11816
  },
11769
11817
  {
11770
11818
  "operation": "time_entries.lastFullMonth",
@@ -11781,7 +11829,9 @@
11781
11829
  "reachable": true,
11782
11830
  "reach": "dedicated tool",
11783
11831
  "reachReason": null,
11784
- "boundedAlternative": null
11832
+ "boundedAlternative": null,
11833
+ "hidden": true,
11834
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
11785
11835
  },
11786
11836
  {
11787
11837
  "operation": "time_entries.lastFullQuarter",
@@ -11798,7 +11848,9 @@
11798
11848
  "reachable": true,
11799
11849
  "reach": "dedicated tool",
11800
11850
  "reachReason": null,
11801
- "boundedAlternative": null
11851
+ "boundedAlternative": null,
11852
+ "hidden": true,
11853
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
11802
11854
  },
11803
11855
  {
11804
11856
  "operation": "time_entries.lastFullWeek",
@@ -11815,7 +11867,9 @@
11815
11867
  "reachable": true,
11816
11868
  "reach": "dedicated tool",
11817
11869
  "reachReason": null,
11818
- "boundedAlternative": null
11870
+ "boundedAlternative": null,
11871
+ "hidden": true,
11872
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
11819
11873
  },
11820
11874
  {
11821
11875
  "operation": "time_entries.moveToTicket",
@@ -11878,8 +11932,8 @@
11878
11932
  "operation": "time_entries.recentTickets",
11879
11933
  "core": false,
11880
11934
  "tool": "autotask_timeEntry_recent_tickets",
11881
- "purpose": "List the distinct tickets a resource logged time against in an inclusive dateWorked window, with entry count, total hours, last worked date and the ticket's number, title, status, assignee and company.",
11882
- "preferredWhen": "Finding the ticket a piece of work was logged against, or which tickets a resource has been working on lately. Not for a total over many groups (operations.aggregate) or the raw entries (time_entries.dateWorkedWindow).",
11935
+ "purpose": "DEPRECATED (since 0.38.0; removed in the next minor; still works): use operations.aggregate('time_entries.query', [{field:'resourceID',op:'eq',value:R},{field:'dateWorked',op:'gte',value:FROM},{field:'dateWorked',op:'lte',value:TO}], {groupBy:['ticketID'], sum:['hoursWorked']}) instead — the group keys carry ticketIDName (ticket number + title); add {field:'ticket.companyID',op:'eq',value:C} for one company. List the distinct tickets a resource logged time against in an inclusive dateWorked window, with entry count, total hours, last worked date and the ticket's number, title, status, assignee and company.",
11936
+ "preferredWhen": "Deprecated: prefer operations.aggregate grouped by ticketID (see purpose). Kept for existing callers until the next minor.",
11883
11937
  "backingOperation": "time_entries.recentTickets",
11884
11938
  "effect": "read",
11885
11939
  "dryRunFirst": false,
@@ -11893,7 +11947,8 @@
11893
11947
  "reachable": true,
11894
11948
  "reach": "dedicated tool",
11895
11949
  "reachReason": null,
11896
- "boundedAlternative": null
11950
+ "boundedAlternative": null,
11951
+ "deprecated": true
11897
11952
  },
11898
11953
  {
11899
11954
  "operation": "time_entries.resolve",
@@ -11929,7 +11984,9 @@
11929
11984
  "reachable": true,
11930
11985
  "reach": "dedicated tool",
11931
11986
  "reachReason": null,
11932
- "boundedAlternative": null
11987
+ "boundedAlternative": null,
11988
+ "hidden": true,
11989
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
11933
11990
  },
11934
11991
  {
11935
11992
  "operation": "time_entries.update",
@@ -11966,7 +12023,9 @@
11966
12023
  "reachable": true,
11967
12024
  "reach": "dedicated tool",
11968
12025
  "reachReason": null,
11969
- "boundedAlternative": null
12026
+ "boundedAlternative": null,
12027
+ "hidden": true,
12028
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
11970
12029
  },
11971
12030
  {
11972
12031
  "operation": "time_entry_attachments.count",
@@ -18508,7 +18567,9 @@
18508
18567
  "reachable": true,
18509
18568
  "reach": "dedicated tool",
18510
18569
  "reachReason": null,
18511
- "boundedAlternative": null
18570
+ "boundedAlternative": null,
18571
+ "hidden": true,
18572
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
18512
18573
  },
18513
18574
  {
18514
18575
  "operation": "invoices.get",
@@ -18595,7 +18656,9 @@
18595
18656
  "reachable": true,
18596
18657
  "reach": "dedicated tool",
18597
18658
  "reachReason": null,
18598
- "boundedAlternative": null
18659
+ "boundedAlternative": null,
18660
+ "hidden": true,
18661
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
18599
18662
  },
18600
18663
  {
18601
18664
  "operation": "invoices.last24h",
@@ -18612,7 +18675,9 @@
18612
18675
  "reachable": true,
18613
18676
  "reach": "dedicated tool",
18614
18677
  "reachReason": null,
18615
- "boundedAlternative": null
18678
+ "boundedAlternative": null,
18679
+ "hidden": true,
18680
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
18616
18681
  },
18617
18682
  {
18618
18683
  "operation": "invoices.last30",
@@ -18629,7 +18694,9 @@
18629
18694
  "reachable": true,
18630
18695
  "reach": "dedicated tool",
18631
18696
  "reachReason": null,
18632
- "boundedAlternative": null
18697
+ "boundedAlternative": null,
18698
+ "hidden": true,
18699
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
18633
18700
  },
18634
18701
  {
18635
18702
  "operation": "invoices.last7",
@@ -18646,7 +18713,9 @@
18646
18713
  "reachable": true,
18647
18714
  "reach": "dedicated tool",
18648
18715
  "reachReason": null,
18649
- "boundedAlternative": null
18716
+ "boundedAlternative": null,
18717
+ "hidden": true,
18718
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
18650
18719
  },
18651
18720
  {
18652
18721
  "operation": "invoices.last90",
@@ -18663,7 +18732,9 @@
18663
18732
  "reachable": true,
18664
18733
  "reach": "dedicated tool",
18665
18734
  "reachReason": null,
18666
- "boundedAlternative": null
18735
+ "boundedAlternative": null,
18736
+ "hidden": true,
18737
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
18667
18738
  },
18668
18739
  {
18669
18740
  "operation": "invoices.lastFullFortnight",
@@ -18680,7 +18751,9 @@
18680
18751
  "reachable": true,
18681
18752
  "reach": "dedicated tool",
18682
18753
  "reachReason": null,
18683
- "boundedAlternative": null
18754
+ "boundedAlternative": null,
18755
+ "hidden": true,
18756
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
18684
18757
  },
18685
18758
  {
18686
18759
  "operation": "invoices.lastFullMonth",
@@ -18697,7 +18770,9 @@
18697
18770
  "reachable": true,
18698
18771
  "reach": "dedicated tool",
18699
18772
  "reachReason": null,
18700
- "boundedAlternative": null
18773
+ "boundedAlternative": null,
18774
+ "hidden": true,
18775
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
18701
18776
  },
18702
18777
  {
18703
18778
  "operation": "invoices.lastFullQuarter",
@@ -18714,7 +18789,9 @@
18714
18789
  "reachable": true,
18715
18790
  "reach": "dedicated tool",
18716
18791
  "reachReason": null,
18717
- "boundedAlternative": null
18792
+ "boundedAlternative": null,
18793
+ "hidden": true,
18794
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
18718
18795
  },
18719
18796
  {
18720
18797
  "operation": "invoices.lastFullWeek",
@@ -18731,7 +18808,9 @@
18731
18808
  "reachable": true,
18732
18809
  "reach": "dedicated tool",
18733
18810
  "reachReason": null,
18734
- "boundedAlternative": null
18811
+ "boundedAlternative": null,
18812
+ "hidden": true,
18813
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
18735
18814
  },
18736
18815
  {
18737
18816
  "operation": "invoices.markupHtml",
@@ -18841,7 +18920,9 @@
18841
18920
  "reachable": true,
18842
18921
  "reach": "dedicated tool",
18843
18922
  "reachReason": null,
18844
- "boundedAlternative": null
18923
+ "boundedAlternative": null,
18924
+ "hidden": true,
18925
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
18845
18926
  },
18846
18927
  {
18847
18928
  "operation": "invoices.update",
@@ -18878,7 +18959,9 @@
18878
18959
  "reachable": true,
18879
18960
  "reach": "dedicated tool",
18880
18961
  "reachReason": null,
18881
- "boundedAlternative": null
18962
+ "boundedAlternative": null,
18963
+ "hidden": true,
18964
+ "hiddenReason": "date-window helper (one date field, no company/contract scope): hidden from default results — prefer <resource>.query with a date filter or operations.aggregate; still callable by exact key"
18882
18965
  },
18883
18966
  {
18884
18967
  "operation": "opportunities.count",
@@ -23252,7 +23335,7 @@
23252
23335
  "operation": "operations.aggregate",
23253
23336
  "core": false,
23254
23337
  "tool": "autotask_aggregate",
23255
- "purpose": "Fold any query surface into groups/sums/totals in one bounded call — or count it with the vendor count endpoint when no folding is needed — with blind-surface and truncation honesty (caps documented: the walk scans at most 2500 rows and top keeps at most 100 groups — a truncated aggregate is a PARTIAL answer, never a tenant-wide total); date fields bucket via the closed groupBy suffix <field>@month | @week | @year (ISO labels, UTC-anchored)",
23338
+ "purpose": "Fold any query surface into groups/sums/totals in one bounded call — or count it with the vendor count endpoint when no folding is needed — with blind-surface and truncation honesty (caps documented: the walk scans at most 2500 rows and top keeps at most 100 groups — a truncated aggregate is a PARTIAL answer, never a tenant-wide total); date fields bucket via the closed groupBy suffix <field>@month | @week | @year (ISO labels, UTC-anchored). Use it for totals, sums, counts and hours per ticket, resource, company, contract or month (group by any field), e.g. time entries hours grouped by ticket and resource",
23256
23339
  "preferredWhen": "For existence checks and totals over any queryable table (count mode is one call vs a 50k-char page); group-by/sum folds the vendor has no endpoint for; a targeted read is cheaper when you need the rows",
23257
23340
  "backingOperation": "operations.aggregate",
23258
23341
  "effect": "read",