@docyrus/docyrus 0.0.19 → 0.0.21

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 (111) hide show
  1. package/agent-loader.js +37 -3
  2. package/agent-loader.js.map +2 -2
  3. package/main.js +498 -93
  4. package/main.js.map +4 -4
  5. package/package.json +14 -4
  6. package/resources/chrome-tools/browser-content.js +103 -0
  7. package/resources/chrome-tools/browser-cookies.js +35 -0
  8. package/resources/chrome-tools/browser-eval.js +53 -0
  9. package/resources/chrome-tools/browser-hn-scraper.js +108 -0
  10. package/resources/chrome-tools/browser-nav.js +44 -0
  11. package/resources/chrome-tools/browser-pick.js +162 -0
  12. package/resources/chrome-tools/browser-screenshot.js +34 -0
  13. package/resources/chrome-tools/browser-start.js +86 -0
  14. package/resources/pi-agent/extensions/answer.ts +532 -0
  15. package/resources/pi-agent/extensions/context.ts +578 -0
  16. package/resources/pi-agent/extensions/control.ts +1779 -0
  17. package/resources/pi-agent/extensions/diff.ts +218 -0
  18. package/resources/pi-agent/extensions/files.ts +199 -0
  19. package/resources/pi-agent/extensions/loop.ts +446 -0
  20. package/resources/pi-agent/extensions/multi-edit.ts +835 -0
  21. package/resources/pi-agent/extensions/notify.ts +88 -0
  22. package/resources/pi-agent/extensions/pi-mcp-adapter/CHANGELOG.md +192 -0
  23. package/resources/pi-agent/extensions/pi-mcp-adapter/LICENSE +21 -0
  24. package/resources/pi-agent/extensions/pi-mcp-adapter/README.md +296 -0
  25. package/resources/pi-agent/extensions/pi-mcp-adapter/app-bridge.bundle.js +67 -0
  26. package/resources/pi-agent/extensions/pi-mcp-adapter/cli.js +108 -0
  27. package/resources/pi-agent/extensions/pi-mcp-adapter/commands.ts +211 -0
  28. package/resources/pi-agent/extensions/pi-mcp-adapter/config.ts +227 -0
  29. package/resources/pi-agent/extensions/pi-mcp-adapter/consent-manager.ts +64 -0
  30. package/resources/pi-agent/extensions/pi-mcp-adapter/direct-tools.ts +301 -0
  31. package/resources/pi-agent/extensions/pi-mcp-adapter/errors.ts +219 -0
  32. package/resources/pi-agent/extensions/pi-mcp-adapter/glimpse-ui.ts +80 -0
  33. package/resources/pi-agent/extensions/pi-mcp-adapter/host-html-template.ts +427 -0
  34. package/resources/pi-agent/extensions/pi-mcp-adapter/index.ts +232 -0
  35. package/resources/pi-agent/extensions/pi-mcp-adapter/init.ts +319 -0
  36. package/resources/pi-agent/extensions/pi-mcp-adapter/lifecycle.ts +93 -0
  37. package/resources/pi-agent/extensions/pi-mcp-adapter/logger.ts +169 -0
  38. package/resources/pi-agent/extensions/pi-mcp-adapter/mcp-panel.ts +713 -0
  39. package/resources/pi-agent/extensions/pi-mcp-adapter/metadata-cache.ts +191 -0
  40. package/resources/pi-agent/extensions/pi-mcp-adapter/npx-resolver.ts +419 -0
  41. package/resources/pi-agent/extensions/pi-mcp-adapter/oauth-handler.ts +56 -0
  42. package/resources/pi-agent/extensions/pi-mcp-adapter/package.json +85 -0
  43. package/resources/pi-agent/extensions/pi-mcp-adapter/paths.ts +29 -0
  44. package/resources/pi-agent/extensions/pi-mcp-adapter/proxy-modes.ts +635 -0
  45. package/resources/pi-agent/extensions/pi-mcp-adapter/resource-tools.ts +17 -0
  46. package/resources/pi-agent/extensions/pi-mcp-adapter/server-manager.ts +330 -0
  47. package/resources/pi-agent/extensions/pi-mcp-adapter/state.ts +41 -0
  48. package/resources/pi-agent/extensions/pi-mcp-adapter/tool-metadata.ts +144 -0
  49. package/resources/pi-agent/extensions/pi-mcp-adapter/tool-registrar.ts +46 -0
  50. package/resources/pi-agent/extensions/pi-mcp-adapter/types.ts +367 -0
  51. package/resources/pi-agent/extensions/pi-mcp-adapter/ui-resource-handler.ts +145 -0
  52. package/resources/pi-agent/extensions/pi-mcp-adapter/ui-server.ts +623 -0
  53. package/resources/pi-agent/extensions/pi-mcp-adapter/ui-session.ts +384 -0
  54. package/resources/pi-agent/extensions/pi-mcp-adapter/ui-stream-types.ts +89 -0
  55. package/resources/pi-agent/extensions/pi-mcp-adapter/utils.ts +75 -0
  56. package/resources/pi-agent/extensions/prompt-editor.ts +1315 -0
  57. package/resources/pi-agent/extensions/prompt-url-widget.ts +158 -0
  58. package/resources/pi-agent/extensions/redraws.ts +24 -0
  59. package/resources/pi-agent/extensions/review.ts +2160 -0
  60. package/resources/pi-agent/extensions/todos.ts +2076 -0
  61. package/resources/pi-agent/extensions/tps.ts +47 -0
  62. package/resources/pi-agent/extensions/whimsical.ts +474 -0
  63. package/resources/pi-agent/prompts/coder-system.md +106 -0
  64. package/resources/pi-agent/skills/changelog-generator/SKILL.md +425 -0
  65. package/resources/pi-agent/skills/docyrus-chrome-devtools-cli/SKILL.md +80 -0
  66. package/resources/pi-agent/skills/docyrus-platform/SKILL.md +71 -0
  67. package/resources/pi-agent/skills/docyrus-platform/references/ai-capabilities.md +43 -0
  68. package/resources/pi-agent/skills/docyrus-platform/references/auth-and-multi-tenancy.md +35 -0
  69. package/resources/pi-agent/skills/docyrus-platform/references/automation-and-workflows.md +30 -0
  70. package/resources/pi-agent/skills/docyrus-platform/references/core-building-blocks.md +53 -0
  71. package/resources/pi-agent/skills/{docyrus-api-dev → docyrus-platform}/references/data-source-query-guide.md +32 -28
  72. package/resources/pi-agent/skills/docyrus-platform/references/developer-tools.md +28 -0
  73. package/resources/pi-agent/skills/docyrus-platform/references/docyrus-cli-usage.md +554 -0
  74. package/resources/pi-agent/skills/{docyrus-api-dev → docyrus-platform}/references/formula-design-guide-llm.md +15 -23
  75. package/resources/pi-agent/skills/docyrus-platform/references/integrations-and-events.md +60 -0
  76. package/resources/pi-agent/skills/docyrus-platform/references/platform-services.md +58 -0
  77. package/resources/pi-agent/skills/docyrus-platform/references/querying-and-data-operations.md +27 -0
  78. package/resources/pi-agent/prompts/coder-append-system.md +0 -19
  79. package/resources/pi-agent/skills/docyrus-ai/SKILL.md +0 -28
  80. package/resources/pi-agent/skills/docyrus-api-dev/SKILL.md +0 -161
  81. package/resources/pi-agent/skills/docyrus-api-dev/references/api-client.md +0 -349
  82. package/resources/pi-agent/skills/docyrus-api-dev/references/authentication.md +0 -238
  83. package/resources/pi-agent/skills/docyrus-api-dev/references/query-and-formulas.md +0 -592
  84. package/resources/pi-agent/skills/docyrus-api-doctor/SKILL.md +0 -70
  85. package/resources/pi-agent/skills/docyrus-api-doctor/references/checklist-details.md +0 -588
  86. package/resources/pi-agent/skills/docyrus-app-dev/SKILL.md +0 -159
  87. package/resources/pi-agent/skills/docyrus-app-dev/references/api-client-and-auth.md +0 -275
  88. package/resources/pi-agent/skills/docyrus-app-dev/references/collections-and-patterns.md +0 -352
  89. package/resources/pi-agent/skills/docyrus-app-dev/references/data-source-query-guide.md +0 -2059
  90. package/resources/pi-agent/skills/docyrus-app-dev/references/formula-design-guide-llm.md +0 -320
  91. package/resources/pi-agent/skills/docyrus-app-dev/references/query-guide.md +0 -525
  92. package/resources/pi-agent/skills/docyrus-app-ui-design/SKILL.md +0 -466
  93. package/resources/pi-agent/skills/docyrus-app-ui-design/references/component-selection-guide.md +0 -602
  94. package/resources/pi-agent/skills/docyrus-app-ui-design/references/icon-usage-guide.md +0 -463
  95. package/resources/pi-agent/skills/docyrus-app-ui-design/references/preferred-components-catalog.md +0 -242
  96. package/resources/pi-agent/skills/docyrus-apps/SKILL.md +0 -54
  97. package/resources/pi-agent/skills/docyrus-architect/SKILL.md +0 -174
  98. package/resources/pi-agent/skills/docyrus-architect/references/custom-query-guide.md +0 -410
  99. package/resources/pi-agent/skills/docyrus-architect/references/data-source-query-guide.md +0 -2059
  100. package/resources/pi-agent/skills/docyrus-architect/references/formula-design-guide-llm.md +0 -320
  101. package/resources/pi-agent/skills/docyrus-architect/references/formula-reference.md +0 -145
  102. package/resources/pi-agent/skills/docyrus-auth/SKILL.md +0 -100
  103. package/resources/pi-agent/skills/docyrus-cli-app/SKILL.md +0 -279
  104. package/resources/pi-agent/skills/docyrus-cli-app/references/cli-manifest.md +0 -532
  105. package/resources/pi-agent/skills/docyrus-cli-app/references/list-query-examples.md +0 -248
  106. package/resources/pi-agent/skills/docyrus-curl/SKILL.md +0 -32
  107. package/resources/pi-agent/skills/docyrus-discover/SKILL.md +0 -63
  108. package/resources/pi-agent/skills/docyrus-ds/SKILL.md +0 -95
  109. package/resources/pi-agent/skills/docyrus-env/SKILL.md +0 -21
  110. package/resources/pi-agent/skills/docyrus-studio/SKILL.md +0 -369
  111. package/resources/pi-agent/skills/docyrus-tui/SKILL.md +0 -15
@@ -1,320 +0,0 @@
1
- # SQL Block Formula Reference
2
-
3
- ## Formula Types
4
-
5
- Two block formula formats:
6
-
7
- **Block Inline** — AST expression in SELECT: `{ alias?: string, inputs: IQueryFormulaBlock[] }`. Detected by `inputs` without `from`/`with`.
8
-
9
- **Block Subquery** — correlated subquery on child table: `{ alias?, inputs, from: string, with: string | Record<string,string>, filters?: IQueryFilterGroup }`. Detected by `from`+`with`.
10
-
11
- Compat wrapper: `{ expression: { from, with, inputs } }` is also accepted.
12
-
13
- ## Block Schema
14
-
15
- Top-level requires exactly 1 element in `inputs[]`. Optional `alias` becomes SQL alias.
16
-
17
- Every block has optional `tz?: string` (timezone) and `cast?: string` (type cast). Processing: compile → tz → cast.
18
-
19
- ## Block Kinds
20
-
21
- ### literal
22
-
23
- `{ kind: "literal", literal: string|number|boolean|Date|null|Array }`
24
-
25
- - Scalars → parameterized `$N`. Arrays → `($1, $2, ...)`.
26
- - Inside `concat`/`concat_ws` parent: auto-casts (`::text`, `::boolean`, `::timestamptz`, `::jsonb`).
27
-
28
- ### column
29
-
30
- `{ kind: "column", name: string|string[] }`
31
-
32
- - Advanced DS: `"alias"."slug"`
33
- - Simple DS custom fields: `"alias".data->>'<field-uuid>'` with auto-cast by field type:
34
- - number/money/duration(decimal≠false) → `::decimal`, (decimal=false) → `::int`
35
- - DB types jsonb/date/time/timestamptz/boolean/int* → `::<type>`, uuid[] → `::jsonb`
36
- - Simple DS static/system fields (in `SIMPLE_STATIC_FIELD_SLUGS`): direct reference. Field not found → error.
37
-
38
- ### builtin
39
-
40
- `{ kind: "builtin", name: "current_date"|"current_time"|"current_timestamp"|"now" }`
41
-
42
- - Emitted as raw SQL. Other names → error.
43
-
44
- ### function
45
-
46
- `{ kind: "function", name: string, inputs?: Block[] }`
47
-
48
- - Validated against allowed functions whitelist. Inputs compiled recursively, joined by commas.
49
- - **Gotcha:** Literal auto-cast only works inside `concat`/`concat_ws`. For `jsonb_build_object` and other functions, add explicit `"cast": "text"` to string literal blocks or Postgres will fail to determine parameter types.
50
-
51
- ### extract
52
-
53
- `{ kind: "extract", part: "year"|"month"|"day"|"hour"|"minute"|"second", inputs: [Block] }`
54
-
55
- - Exactly 1 input required.
56
- - SQL: `extract(<part> from <expr>)`
57
-
58
- ### aggregate
59
-
60
- `{ kind: "aggregate", name: "count"|"sum"|"avg"|"min"|"max"|"jsonb_agg"|"json_agg"|"array_agg", distinct?: boolean, inputs: Block[] }`
61
-
62
- - `count` with empty or omitted inputs → `count(*)`. For count specifically, `inputs` is optional.
63
- - `distinct` → `DISTINCT` keyword.
64
-
65
- ### math
66
-
67
- `{ kind: "math", op: "+"|"-"|"*"|"/"|"%", inputs: Block[] }`
68
-
69
- - Min 2 operands. Left-associative with parens: `((a op b) op c)`.
70
-
71
- ### case
72
-
73
- `{ kind: "case", cases: [{when: Block, then: Block}], else?: Block }`
74
-
75
- - Min 1 case required. `else` optional (defaults NULL).
76
-
77
- ### compare
78
-
79
- `{ kind: "compare", op: "="|"!="|"<>"|">"|"<"|">="|"<="|"like"|"ilike"|"in"|"not in"|"not_in", left: Block, right: Block }`
80
-
81
- - `in`/`not in`: `left in right`. `not_in` accepted as alias but prefer `"not in"` (with space).
82
- - `ilike` auto-converted to `like` for MySQL dialect.
83
-
84
- ### boolean
85
-
86
- `{ kind: "boolean", op: "and"|"or"|"not", inputs: Block[] }`
87
-
88
- - `not`: exactly 1 input → `not (<expr>)`. `and`/`or`: min 2 → `((<a>) op (<b>))`.
89
-
90
- ## Subquery Details
91
-
92
- - `from`: child table full slug (`appSlug_tableSlug`), matched via `dataSource.children`.
93
- - `with` (string): child field joins to parent `id`. `with` (object): `{ childField: parentField }`.
94
- - Simple child DS: table rewritten to `tenant_record`, fields use `data->>'uuid'` refs.
95
- - Optional `filters` apply WHERE on child table.
96
- - Child alias: `t0_child`. Parent alias: `t0`.
97
-
98
- ## Allowed Functions (Postgres)
99
-
100
- **String**: length, lower, upper, substr, replace, concat, trim, ltrim, rtrim, btrim, split_part, initcap, reverse, strpos, lpad, rpad
101
-
102
- **Number**: abs, ceil, floor, round, sqrt, power, mod, gcd, lcm, exp, ln, log, log10, log1p, pi, sign, width_bucket, trunc, greatest, least
103
-
104
- **Date/Time**: now, age, clock_timestamp, date_part, date_trunc, extract, isfinite, justify_days, justify_hours, make_date, make_time, make_timestamp, make_timestamptz, timeofday, to_timestamp, to_char, to_date, to_time
105
-
106
- **Utility**: coalesce
107
-
108
- **JSON/JSONB**: jsonb_array_length, jsonb_extract_path, jsonb_extract_path_text, jsonb_object_keys, jsonb_build_object, json_build_object, jsonb_agg, json_agg, array_agg, array_to_json, row_to_json
109
-
110
- **Aggregates**: count, sum, avg, min, max, jsonb_agg, json_agg, array_agg
111
-
112
- ## Cast Types
113
-
114
- Allowed: int, int2, int4, int8, bigint, real, float, float4, float8, numeric, double, decimal, money, timestamp, timestamptz, date, time, interval, bool, boolean, uuid, text (+ array variants like `int[]`, `text[]`).
115
-
116
- ## Timezone
117
-
118
- `tz` property: validated `/^[a-zA-Z0-9_]+$/`. SQL: `<expr> at time zone '<tz>'`. Column/function blocks omit outer parens.
119
-
120
- ## Validation Errors
121
-
122
- | Condition | Error |
123
- |---|---|
124
- | Empty inputs | "Formula must have at least one input block" |
125
- | >1 root input | "Multiple input blocks not yet supported" |
126
- | Bad function | `Function "${name}" is not allowed for dialect "${dialect}"` |
127
- | Bad aggregate | `Aggregate function "${name}" is not allowed` |
128
- | Extract ≠1 input | "EXTRACT requires exactly one input expression" |
129
- | Math <2 ops | "Math operations require at least 2 operands" |
130
- | NOT ≠1 op | "NOT operation requires exactly one operand" |
131
- | AND/OR <2 ops | "${OP} operation requires at least 2 operands" |
132
- | CASE 0 whens | "CASE expression must have at least one WHEN clause" |
133
- | Bad tz | "Unsupported timezone: ${tz}" |
134
- | Bad builtin | "Unsupported formula function: ${name}" |
135
-
136
- ## SelectQueryBuilder Integration
137
-
138
- 1. Formulas in `ISelectQueryParams.formulas` as `Record<string, ISelectQueryFormula>`.
139
- 2. Column alias matching formula key → formula replaces column ref in SELECT.
140
- 3. Dispatch: `from`/`expression` → `buildBlockFormula()` (subquery), `inputs` only → `buildBlockFormula()` (inline).
141
- 4. Calculations with `func:"formula"` also route through `buildFormula()`.
142
- 5. `usedFormulas` set prevents duplicate application across SELECT and aggregations.
143
- 6. Subquery formulas trigger async `resolveChildDatasources()` before build.
144
-
145
- ## Examples
146
-
147
- **Inline math** (balance / 100):
148
-
149
- ```json
150
- { "inputs": [{ "kind": "math", "op": "/", "inputs": [{ "kind": "column", "name": "balance" }, { "kind": "literal", "literal": 100 }] }] }
151
- ```
152
-
153
- **Formatted date** (to_char):
154
-
155
- ```json
156
- { "inputs": [{ "kind": "function", "name": "to_char", "inputs": [{ "kind": "column", "name": "created_on" }, { "kind": "literal", "literal": "DD/MM/YYYY" }] }] }
157
- ```
158
-
159
- **Subquery count**:
160
-
161
- ```json
162
- { "from": "app_child", "with": "parent_id", "inputs": [{ "kind": "aggregate", "name": "count", "inputs": [] }] }
163
- ```
164
-
165
- **Subquery count with distinct**:
166
-
167
- ```json
168
- { "expression": { "from": "app_child_table", "with": "parent_field", "inputs": [{ "kind": "aggregate", "name": "count", "distinct": true, "inputs": [{ "kind": "column", "name": "id" }] }] } }
169
- ```
170
-
171
- **Multi-field subquery join**:
172
-
173
- ```json
174
- { "from": "app_child", "with": { "child_field1": "parent_field1", "child_field2": "parent_field2" }, "inputs": [{ "kind": "aggregate", "name": "sum", "inputs": [{ "kind": "column", "name": "amount" }] }] }
175
- ```
176
-
177
- **CASE with AND**:
178
-
179
- ```json
180
- { "inputs": [{ "kind": "case", "cases": [{ "when": { "kind": "boolean", "op": "and", "inputs": [{ "kind": "compare", "op": ">", "left": { "kind": "column", "name": "price" }, "right": { "kind": "literal", "literal": 100 } }, { "kind": "compare", "op": "ilike", "left": { "kind": "column", "name": "name" }, "right": { "kind": "literal", "literal": "%pro%" } }] }, "then": { "kind": "literal", "literal": "premium" } }], "else": { "kind": "literal", "literal": "standard" } }] }
181
- ```
182
-
183
- **Multi-branch CASE** (tier assignment):
184
-
185
- ```json
186
- { "inputs": [{ "kind": "case", "cases": [{ "when": { "kind": "compare", "op": ">=", "left": { "kind": "column", "name": "revenue" }, "right": { "kind": "literal", "literal": 100000 } }, "then": { "kind": "literal", "literal": "enterprise" } }, { "when": { "kind": "compare", "op": ">=", "left": { "kind": "column", "name": "revenue" }, "right": { "kind": "literal", "literal": 10000 } }, "then": { "kind": "literal", "literal": "business" } }, { "when": { "kind": "compare", "op": ">=", "left": { "kind": "column", "name": "revenue" }, "right": { "kind": "literal", "literal": 1000 } }, "then": { "kind": "literal", "literal": "starter" } }], "else": { "kind": "literal", "literal": "free" } }] }
187
- ```
188
-
189
- **Nested aggregate**: `round(sum(qty * price), 2)`:
190
-
191
- ```json
192
- { "alias": "total", "inputs": [{ "kind": "function", "name": "round", "inputs": [{ "kind": "aggregate", "name": "sum", "inputs": [{ "kind": "math", "op": "*", "inputs": [{ "kind": "column", "name": "qty" }, { "kind": "column", "name": "price" }] }] }, { "kind": "literal", "literal": 2 }] }] }
193
- ```
194
-
195
- **Timezone**: `to_char(now() at time zone 'UTC', 'YYYY-MM-DD')`:
196
-
197
- ```json
198
- { "inputs": [{ "kind": "function", "name": "to_char", "inputs": [{ "kind": "function", "name": "now", "tz": "UTC" }, { "kind": "literal", "literal": "YYYY-MM-DD" }] }] }
199
- ```
200
-
201
- **COALESCE** (null handling):
202
-
203
- ```json
204
- { "inputs": [{ "kind": "function", "name": "coalesce", "inputs": [{ "kind": "column", "name": "description" }, { "kind": "literal", "literal": "No description" }] }] }
205
- ```
206
-
207
- **Subquery with filters** (count active children):
208
-
209
- ```json
210
- { "from": "app_child_table", "with": "parent_id", "filters": { "rules": [{ "field": "status", "operator": "=", "value": "active" }] }, "inputs": [{ "kind": "aggregate", "name": "count", "inputs": [] }] }
211
- ```
212
-
213
- **String concatenation with initcap**:
214
-
215
- ```json
216
- { "inputs": [{ "kind": "function", "name": "initcap", "inputs": [{ "kind": "function", "name": "concat", "inputs": [{ "kind": "column", "name": "first_name" }, { "kind": "literal", "literal": " " }, { "kind": "column", "name": "last_name" }] }] }] }
217
- ```
218
-
219
- **Percentage with cast**: `round(completed/total * 100, 2)`:
220
-
221
- ```json
222
- { "inputs": [{ "kind": "function", "name": "round", "inputs": [{ "kind": "math", "op": "*", "inputs": [{ "kind": "math", "op": "/", "inputs": [{ "kind": "column", "name": "completed_tasks", "cast": "decimal" }, { "kind": "function", "name": "greatest", "inputs": [{ "kind": "column", "name": "total_tasks", "cast": "decimal" }, { "kind": "literal", "literal": 1 }] }] }, { "kind": "literal", "literal": 100 }] }, { "kind": "literal", "literal": 2 }] }] }
223
- ```
224
-
225
- **Days since created**: `date_part('day', age(now, created_on))::int`:
226
-
227
- ```json
228
- { "inputs": [{ "kind": "function", "name": "date_part", "inputs": [{ "kind": "literal", "literal": "day" }, { "kind": "function", "name": "age", "inputs": [{ "kind": "builtin", "name": "now" }, { "kind": "column", "name": "created_on" }] }], "cast": "int" }] }
229
- ```
230
-
231
- **Boolean NOT with OR** (is_active = not archived or deleted):
232
-
233
- ```json
234
- { "inputs": [{ "kind": "boolean", "op": "not", "inputs": [{ "kind": "boolean", "op": "or", "inputs": [{ "kind": "compare", "op": "=", "left": { "kind": "column", "name": "is_archived" }, "right": { "kind": "literal", "literal": true } }, { "kind": "compare", "op": "=", "left": { "kind": "column", "name": "is_deleted" }, "right": { "kind": "literal", "literal": true } }] }] }] }
235
- ```
236
-
237
- **Subquery sum with filters** (outstanding invoice amount):
238
-
239
- ```json
240
- { "from": "billing_invoice_line", "with": "invoice_id", "filters": { "combinator": "and", "rules": [{ "field": "status", "operator": "!=", "value": "paid", "filterType": "ALPHA" }, { "field": "amount", "operator": ">", "value": 0, "filterType": "NUMERIC" }] }, "inputs": [{ "kind": "function", "name": "coalesce", "inputs": [{ "kind": "aggregate", "name": "sum", "inputs": [{ "kind": "column", "name": "amount" }] }, { "kind": "literal", "literal": 0 }] }] }
241
- ```
242
-
243
- **Extract year-month** (concat year + padded month):
244
-
245
- ```json
246
- { "inputs": [{ "kind": "function", "name": "concat", "inputs": [{ "kind": "extract", "part": "year", "inputs": [{ "kind": "column", "name": "created_on" }], "cast": "text" }, { "kind": "literal", "literal": "-" }, { "kind": "function", "name": "lpad", "inputs": [{ "kind": "extract", "part": "month", "inputs": [{ "kind": "column", "name": "created_on" }], "cast": "text" }, { "kind": "literal", "literal": 2 }, { "kind": "literal", "literal": "0" }] }] }] }
247
- ```
248
-
249
- **JSONB extraction**:
250
-
251
- ```json
252
- { "inputs": [{ "kind": "function", "name": "jsonb_extract_path_text", "inputs": [{ "kind": "column", "name": "address" }, { "kind": "literal", "literal": "country" }] }] }
253
- ```
254
-
255
- **Weighted average**: `sum(score * weight) / greatest(sum(weight), 1)`:
256
-
257
- ```json
258
- { "inputs": [{ "kind": "math", "op": "/", "inputs": [{ "kind": "aggregate", "name": "sum", "inputs": [{ "kind": "math", "op": "*", "inputs": [{ "kind": "column", "name": "score" }, { "kind": "column", "name": "weight" }] }] }, { "kind": "function", "name": "greatest", "inputs": [{ "kind": "aggregate", "name": "sum", "inputs": [{ "kind": "column", "name": "weight" }] }, { "kind": "literal", "literal": 1 }] }], "cast": "decimal" }] }
259
- ```
260
-
261
- **Date truncation** (period grouping by month):
262
-
263
- ```json
264
- { "inputs": [{ "kind": "function", "name": "date_trunc", "inputs": [{ "kind": "literal", "literal": "month" }, { "kind": "column", "name": "order_date" }] }] }
265
- ```
266
-
267
- **Multiple subquery formulas** (project with total + open task counts, using compat wrapper):
268
-
269
- ```json
270
- {
271
- "columns": "id, name, total_tasks, open_tasks",
272
- "formulas": [
273
- {
274
- "key": "total_tasks",
275
- "expression": {
276
- "expression": {
277
- "from": "base_task", "with": "project",
278
- "inputs": [{ "kind": "aggregate", "name": "count", "inputs": [{ "kind": "column", "name": "id" }] }]
279
- }
280
- }
281
- },
282
- {
283
- "key": "open_tasks",
284
- "expression": {
285
- "expression": {
286
- "from": "base_task", "with": "project",
287
- "inputs": [{ "kind": "aggregate", "name": "count", "inputs": [{ "kind": "column", "name": "id" }] }],
288
- "filters": { "rules": [{ "field": "status", "operator": "not_in", "value": ["<completed_uuid>", "<cancelled_uuid>"] }], "combinator": "and" }
289
- }
290
- }
291
- }
292
- ]
293
- }
294
- ```
295
-
296
- → Each formula produces a correlated subquery: `(SELECT count("t0_child"."id") FROM ... WHERE "t0_child"."project" = "t0"."id" [AND status filter])`. No GROUP BY needed.
297
-
298
- **Combined aggregations via jsonb_build_object** (pack total + open counts into one JSON column, one subquery):
299
-
300
- ```json
301
- {
302
- "key": "task_stats",
303
- "expression": {
304
- "expression": {
305
- "from": "base_task", "with": "project",
306
- "inputs": [{
307
- "kind": "function", "name": "jsonb_build_object",
308
- "inputs": [
309
- { "kind": "literal", "literal": "total", "cast": "text" },
310
- { "kind": "aggregate", "name": "count", "inputs": [{ "kind": "column", "name": "id" }] },
311
- { "kind": "literal", "literal": "open", "cast": "text" },
312
- { "kind": "aggregate", "name": "count", "inputs": [{ "kind": "case", "cases": [{ "when": { "kind": "compare", "op": "not in", "left": { "kind": "column", "name": "status" }, "right": { "kind": "literal", "literal": ["<completed_uuid>", "<cancelled_uuid>"] } }, "then": { "kind": "column", "name": "id" } }] }] }
313
- ]
314
- }]
315
- }
316
- }
317
- }
318
- ```
319
-
320
- → Result: `{ "task_stats": { "total": 6, "open": 2 } }`. `count(CASE WHEN ... THEN id END)` skips NULLs (no `else`) to count conditionally. `"cast": "text"` on literal keys is **required** for `jsonb_build_object`.
@@ -1,145 +0,0 @@
1
- # SQL Block Formula Reference
2
-
3
- ## Formula Types
4
-
5
- `ISelectQueryFormula = IQuerySimpleFormula | IQueryBlockFormula`
6
-
7
- **Simple** — legacy flat function call: `{ func: string, args: (string|number)[] }`. Column refs use `{col}` syntax. Detected by `func` property.
8
-
9
- **Block Inline** — AST expression in SELECT: `{ alias?: string, inputs: IQueryFormulaBlock[] }`. Detected by `inputs` without `from`/`with`.
10
-
11
- **Block Subquery** — correlated subquery on child table: `{ alias?, inputs, from: string, with: string | Record<string,string>, filters?: IQueryFilterGroup }`. Detected by `from`+`with`.
12
-
13
- Compat wrapper: `{ expression: { from, with, inputs } }` is also accepted.
14
-
15
- ## Block Schema
16
-
17
- Top-level requires exactly 1 element in `inputs[]`. Optional `alias` becomes SQL alias.
18
-
19
- Every block has optional `tz?: string` (timezone) and `cast?: string` (type cast). Processing: compile → tz → cast.
20
-
21
- ## Block Kinds
22
-
23
- ### literal
24
- `{ kind: "literal", literal: string|number|boolean|Date|null|Array }`
25
- - Scalars → parameterized `$N`. Arrays → `($1, $2, ...)`.
26
- - Inside `concat`/`concat_ws` parent: auto-casts (`::text`, `::boolean`, `::timestamptz`, `::jsonb`).
27
-
28
- ### column
29
- `{ kind: "column", name: string|string[] }`
30
- - Advanced DS: `"alias"."slug"`
31
- - Simple DS custom fields: `"alias".data->>'<field-uuid>'` with auto-cast by field type:
32
- - number/money/duration(decimal≠false) → `::decimal`, (decimal=false) → `::int`
33
- - DB types jsonb/date/time/timestamptz/boolean/int* → `::<type>`, uuid[] → `::jsonb`
34
- - Simple DS system fields: direct reference. Field not found → error.
35
-
36
- ### builtin
37
- `{ kind: "builtin", name: "current_date"|"current_time"|"current_timestamp"|"now" }`
38
- - Emitted as raw SQL. Other names → error.
39
-
40
- ### function
41
- `{ kind: "function", name: string, inputs?: Block[] }`
42
- - Validated against per-dialect whitelist. Inputs compiled recursively, joined by commas.
43
-
44
- ### extract
45
- `{ kind: "extract", part: "year"|"month"|"day"|"hour"|"minute"|"second", inputs: [Block] }`
46
- - Exactly 1 input required.
47
- - Postgres/MySQL: `extract(<part> from <expr>)`. ClickHouse: `toYear(...)`, `toMonth(...)`, etc.
48
-
49
- ### aggregate
50
- `{ kind: "aggregate", name: "count"|"sum"|"avg"|"min"|"max"|"jsonb_agg"|"json_agg"|"array_agg", distinct?: boolean, inputs: Block[] }`
51
- - `count` with empty inputs → `count(*)`. `distinct` → `DISTINCT` keyword.
52
-
53
- ### math
54
- `{ kind: "math", op: "+"|"-"|"*"|"/"|"%", inputs: Block[] }`
55
- - Min 2 operands. Left-associative with parens: `((a op b) op c)`.
56
-
57
- ### case
58
- `{ kind: "case", cases: [{when: Block, then: Block}], else?: Block }`
59
- - Min 1 case required. `else` optional (defaults NULL).
60
-
61
- ### compare
62
- `{ kind: "compare", op: "="|"!="|"<>"|">"|"<"|">="|"<="|"like"|"ilike"|"in"|"not in", left: Block, right: Block }`
63
- - `in`/`not in`: `left in right`. `ilike` → `like` on MySQL.
64
-
65
- ### boolean
66
- `{ kind: "boolean", op: "and"|"or"|"not", inputs: Block[] }`
67
- - `not`: exactly 1 input → `not (<expr>)`. `and`/`or`: min 2 → `((<a>) op (<b>))`.
68
-
69
- ## Subquery Details
70
-
71
- - `from`: child table full slug (`appSlug_tableSlug`), matched via `dataSource.children`.
72
- - `with` (string): child field joins to parent `id`. `with` (object): `{ childField: parentField }`.
73
- - Simple child DS: table rewritten to `tenant_record`, fields use `data->>'uuid'` refs.
74
- - Optional `filters` apply WHERE on child table.
75
- - Child alias: `t0_child`. Parent alias: `t0`.
76
-
77
- ## Allowed Functions
78
-
79
- **Postgres**: length, lower, upper, substr, replace, concat, trim, ltrim, rtrim, btrim, split_part, initcap, reverse, strpos, lpad, rpad, abs, ceil, floor, round, sqrt, power, mod, gcd, lcm, exp, ln, log, log10, log1p, pi, sign, width_bucket, trunc, greatest, least, now, age, clock_timestamp, date_part, date_trunc, extract, isfinite, justify_days, justify_hours, make_date, make_time, make_timestamp, make_timestamptz, timeofday, to_timestamp, to_char, to_date, to_time, coalesce, jsonb_array_length, jsonb_extract_path, jsonb_extract_path_text, jsonb_object_keys, jsonb_build_object, json_build_object, jsonb_agg, json_agg, array_agg, array_to_json, row_to_json
80
-
81
- **MySQL**: length, lower, upper, substr, substring, replace, concat, trim, ltrim, rtrim, left, right, reverse, locate, lpad, rpad, abs, ceil, ceiling, floor, round, sqrt, power, pow, mod, exp, ln, log, log10, sign, truncate, greatest, least, now, curdate, curtime, current_date, current_time, current_timestamp, date, time, year, month, day, hour, minute, second, date_format, str_to_date, unix_timestamp, from_unixtime, coalesce, json_value, json_extract, ifnull, format
82
-
83
- **ClickHouse**: length, lower, upper, substr, substring, replace, concat, trim, ltrim, rtrim, reverse, position, leftPad, rightPad, abs, ceil, floor, round, sqrt, pow, mod, exp, ln, log, log10, sign, trunc, greatest, least, now, today, yesterday, toYear, toMonth, toDayOfMonth, toHour, toMinute, toSecond, formatDateTime, parseDateTime, coalesce, ifnull, multiif
84
-
85
- **Aggregates** (all dialects): count, sum, avg, min, max, jsonb_agg, json_agg, array_agg
86
-
87
- ## Cast Types
88
-
89
- Allowed: int, int2, int4, int8, bigint, real, float, float4, float8, numeric, double, decimal, money, timestamp, timestamptz, date, time, interval, bool, boolean, uuid, text (+ array variants like `int[]`, `text[]`).
90
-
91
- ## Timezone
92
-
93
- `tz` property: validated `/^[a-zA-Z0-9_]+$/`. Postgres: `<expr> at time zone '<tz>'`. Column/function blocks omit outer parens.
94
-
95
- ## Validation Errors
96
-
97
- | Condition | Error |
98
- |---|---|
99
- | Empty inputs | "Formula must have at least one input block" |
100
- | >1 root input | "Multiple input blocks not yet supported" |
101
- | Bad function | `Function "${name}" is not allowed for dialect "${dialect}"` |
102
- | Bad aggregate | `Aggregate function "${name}" is not allowed` |
103
- | Extract ≠1 input | "EXTRACT requires exactly one input expression" |
104
- | Math <2 ops | "Math operations require at least 2 operands" |
105
- | NOT ≠1 op | "NOT operation requires exactly one operand" |
106
- | AND/OR <2 ops | "${OP} operation requires at least 2 operands" |
107
- | CASE 0 whens | "CASE expression must have at least one WHEN clause" |
108
- | Bad tz | "Unsupported timezone: ${tz}" |
109
- | Bad builtin | "Unsupported formula function: ${name}" |
110
-
111
- ## SelectQueryBuilder Integration
112
-
113
- 1. Formulas in `ISelectQueryParams.formulas` as `Record<string, ISelectQueryFormula>`.
114
- 2. Column alias matching formula key → formula replaces column ref in SELECT.
115
- 3. Dispatch: `func` → `buildSimpleFormula()`, `from`/`expression` → `buildBlockFormula()` (subquery), `inputs` only → `buildBlockFormula()` (inline).
116
- 4. Calculations with `func:"formula"` also route through `buildFormula()`.
117
- 5. `usedFormulas` set prevents duplicate application across SELECT and aggregations.
118
- 6. Subquery formulas trigger async `resolveChildDatasources()` before build.
119
-
120
- ## Examples
121
-
122
- **Inline math** (balance / 100):
123
- ```json
124
- { "inputs": [{ "kind": "math", "op": "/", "inputs": [{ "kind": "column", "name": "balance" }, { "kind": "literal", "literal": 100 }] }] }
125
- ```
126
-
127
- **Subquery count**:
128
- ```json
129
- { "from": "app_child", "with": "parent_id", "inputs": [{ "kind": "aggregate", "name": "count", "inputs": [] }] }
130
- ```
131
-
132
- **CASE with AND**:
133
- ```json
134
- { "inputs": [{ "kind": "case", "cases": [{ "when": { "kind": "boolean", "op": "and", "inputs": [{ "kind": "compare", "op": ">", "left": { "kind": "column", "name": "price" }, "right": { "kind": "literal", "literal": 100 } }, { "kind": "compare", "op": "ilike", "left": { "kind": "column", "name": "name" }, "right": { "kind": "literal", "literal": "%pro%" } }] }, "then": { "kind": "literal", "literal": "premium" } }], "else": { "kind": "literal", "literal": "standard" } }] }
135
- ```
136
-
137
- **Nested aggregate**: `round(sum(qty * price), 2)`:
138
- ```json
139
- { "alias": "total", "inputs": [{ "kind": "function", "name": "round", "inputs": [{ "kind": "aggregate", "name": "sum", "inputs": [{ "kind": "math", "op": "*", "inputs": [{ "kind": "column", "name": "qty" }, { "kind": "column", "name": "price" }] }] }, { "kind": "literal", "literal": 2 }] }] }
140
- ```
141
-
142
- **Timezone**: `to_char(now() at time zone 'UTC', 'YYYY-MM-DD')`:
143
- ```json
144
- { "inputs": [{ "kind": "function", "name": "to_char", "inputs": [{ "kind": "function", "name": "now", "tz": "UTC" }, { "kind": "literal", "literal": "YYYY-MM-DD" }] }] }
145
- ```
@@ -1,100 +0,0 @@
1
- ---
2
- name: docyrus-auth
3
- description: Authentication commands. List saved user accounts for current API base URL, Switch active account by user ID, Authorize CLI using OAuth2 device flow, Revoke and clear all tenant sessions for active account, Set custom access and refresh tokens for the active environment, List available tenants for an account, Switch active tenant for an account, Return current authenticated user (/v1/users/me). Run `docyrus auth --help` for usage details.
4
- command: docyrus auth
5
- ---
6
-
7
- # docyrus auth accounts list
8
-
9
- List saved user accounts for current API base URL
10
-
11
- ---
12
-
13
- # docyrus auth accounts use
14
-
15
- Switch active account by user ID
16
-
17
- ## Options
18
-
19
- | Flag | Type | Default | Description |
20
- |------|------|---------|-------------|
21
- | `--userId` | `string` | | User ID to activate |
22
-
23
- ---
24
-
25
- # docyrus auth login
26
-
27
- Authorize CLI using OAuth2 device flow
28
-
29
- ## Options
30
-
31
- | Flag | Type | Default | Description |
32
- |------|------|---------|-------------|
33
- | `--clientId` | `string` | | OAuth2 client id |
34
- | `--scope` | `string` | `openid email profile offline_access ReadWrite.All User.ReadWrite Users.ReadWrite.All Tenant.Read Teams.Read.All DS.ReadWrite.All Docs.ReadWrite.All Architect.ReadWrite.All AI.ReadWrite.All` | OAuth2 scopes |
35
- | `--accessToken` | `string` | | Manual access token; skips device flow |
36
- | `--refreshToken` | `string` | | Manual refresh token used with --accessToken |
37
-
38
- ---
39
-
40
- # docyrus auth logout
41
-
42
- Revoke and clear all tenant sessions for active account
43
-
44
- ## Options
45
-
46
- | Flag | Type | Default | Description |
47
- |------|------|---------|-------------|
48
- | `--clientId` | `string` | | OAuth2 client id override |
49
-
50
- ---
51
-
52
- # docyrus auth set-tokens
53
-
54
- Set custom access and refresh tokens for the active environment
55
-
56
- ## Options
57
-
58
- | Flag | Type | Default | Description |
59
- |------|------|---------|-------------|
60
- | `--clientId` | `string` | | OAuth2 client id |
61
- | `--scope` | `string` | `openid email profile offline_access ReadWrite.All User.ReadWrite Users.ReadWrite.All Tenant.Read Teams.Read.All DS.ReadWrite.All Docs.ReadWrite.All Architect.ReadWrite.All AI.ReadWrite.All` | OAuth2 scopes |
62
- | `--accessToken` | `string` | | Custom access token |
63
- | `--refreshToken` | `string` | | Custom refresh token |
64
-
65
- ---
66
-
67
- # docyrus auth tenants list
68
-
69
- List available tenants for an account
70
-
71
- ## Options
72
-
73
- | Flag | Type | Default | Description |
74
- |------|------|---------|-------------|
75
- | `--userId` | `string` | | User ID; defaults to active account |
76
-
77
- ---
78
-
79
- # docyrus auth tenants use
80
-
81
- Switch active tenant for an account
82
-
83
- ## Arguments
84
-
85
- | Name | Type | Required | Description |
86
- |------|------|----------|-------------|
87
- | `tenantSelector` | `string` | yes | Tenant selector: tenant no or UUID tenant id |
88
-
89
- ## Options
90
-
91
- | Flag | Type | Default | Description |
92
- |------|------|---------|-------------|
93
- | `--userId` | `string` | | User ID; defaults to active account |
94
- | `--scope` | `string` | | Scope used only when tenant bootstrap login is required |
95
-
96
- ---
97
-
98
- # docyrus auth who
99
-
100
- Return current authenticated user (/v1/users/me)