@agent-native/core 0.101.5 → 0.101.7
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 +1 -1
- package/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +12 -0
- package/corpus/core/docs/content/locales/ar-SA/pure-agent-apps.mdx +2 -2
- package/corpus/core/docs/content/locales/de-DE/pure-agent-apps.mdx +2 -2
- package/corpus/core/docs/content/locales/es-ES/pure-agent-apps.mdx +2 -2
- package/corpus/core/docs/content/locales/fr-FR/pure-agent-apps.mdx +2 -2
- package/corpus/core/docs/content/locales/hi-IN/pure-agent-apps.mdx +2 -2
- package/corpus/core/docs/content/locales/ja-JP/pure-agent-apps.mdx +2 -2
- package/corpus/core/docs/content/locales/ko-KR/pure-agent-apps.mdx +2 -2
- package/corpus/core/docs/content/locales/pt-BR/pure-agent-apps.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-CN/pure-agent-apps.mdx +2 -2
- package/corpus/core/docs/content/locales/zh-TW/pure-agent-apps.mdx +2 -2
- package/corpus/core/docs/content/pure-agent-apps.mdx +58 -14
- package/corpus/core/package.json +1 -1
- package/corpus/core/src/a2a/artifact-response.ts +255 -12
- package/corpus/core/src/agent/thread-data-builder.ts +84 -11
- package/corpus/core/src/integrations/a2a-continuation-processor.ts +99 -7
- package/corpus/core/src/integrations/adapters/discord.ts +3 -1
- package/corpus/core/src/integrations/adapters/email.ts +4 -1
- package/corpus/core/src/integrations/adapters/google-docs.ts +4 -1
- package/corpus/core/src/integrations/adapters/microsoft-teams.ts +3 -1
- package/corpus/core/src/integrations/adapters/slack.ts +38 -9
- package/corpus/core/src/integrations/adapters/telegram.ts +32 -10
- package/corpus/core/src/integrations/adapters/whatsapp.ts +5 -1
- package/corpus/core/src/integrations/index.ts +1 -0
- package/corpus/core/src/integrations/types.ts +9 -2
- package/corpus/core/src/integrations/webhook-handler.ts +69 -45
- package/corpus/core/src/server/agent-chat/action-filters-a2a.ts +1 -0
- package/corpus/templates/analytics/AGENTS.md +6 -0
- package/corpus/templates/analytics/README.md +1 -1
- package/corpus/templates/analytics/actions/data-source-status.ts +19 -1
- package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +5 -1
- package/corpus/templates/analytics/app/routes/_index.tsx +2 -2
- package/corpus/templates/analytics/changelog/2026-07-14-analytics-chat-guides-you-to-connect-a-data-source-with-a-di.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-14-analytics-landing-pages-now-clearly-position-the-app-as-an-o.md +6 -0
- package/corpus/templates/analytics/changelog/2026-07-15-daily-dashboard-emails-now-include-the-complete-dashboard-sc.md +6 -0
- package/corpus/templates/analytics/server/jobs/dashboard-report.ts +8 -1
- package/corpus/templates/analytics/server/lib/dashboard-report.ts +64 -12
- package/corpus/templates/analytics/server/lib/real-data-actions.ts +15 -3
- package/corpus/templates/analytics/server/plugins/agent-chat.ts +364 -4
- package/corpus/templates/clips/app/components/dictate/vocabulary-section.tsx +1 -0
- package/corpus/templates/clips/app/components/library/folder-tree.tsx +12 -9
- package/corpus/templates/clips/app/components/library/library-layout.tsx +19 -16
- package/corpus/templates/clips/app/routes/_app.spaces._index.tsx +13 -9
- package/corpus/templates/clips/changelog/2026-07-15-folders-and-sidebar-links-are-clickable-again-immediately-af.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-hovering-a-truncated-folder-name-now-shows-the-full-name.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-space-creation-controls-are-now-shown-only-to-organization-a.md +6 -0
- package/corpus/templates/clips/changelog/2026-07-15-vocabulary-terms-can-now-be-deleted-from-the-dictation-dicti.md +6 -0
- package/corpus/templates/clips/desktop/src/styles.css +23 -1
- package/corpus/templates/clips/desktop/src-tauri/src/whisper_speech.rs +49 -7
- package/corpus/templates/clips/server/lib/recordings.ts +5 -2
- package/corpus/templates/content/.agents/skills/content/SKILL.md +31 -0
- package/corpus/templates/content/.agents/skills/document-editing/SKILL.md +35 -21
- package/corpus/templates/content/AGENTS.md +29 -7
- package/corpus/templates/content/actions/_database-source-utils.ts +30 -16
- package/corpus/templates/content/actions/_database-utils.ts +15 -1
- package/corpus/templates/content/actions/_local-file-documents.ts +53 -1
- package/corpus/templates/content/actions/_property-utils.ts +7 -1
- package/corpus/templates/content/actions/configure-document-property.ts +11 -0
- package/corpus/templates/content/actions/create-content-database.ts +11 -0
- package/corpus/templates/content/actions/create-document.ts +9 -0
- package/corpus/templates/content/actions/create-inline-content-database.ts +3 -0
- package/corpus/templates/content/actions/export-content-source.ts +1 -0
- package/corpus/templates/content/actions/get-content-database.ts +13 -1
- package/corpus/templates/content/actions/get-document.ts +12 -2
- package/corpus/templates/content/actions/import-content-source.ts +6 -0
- package/corpus/templates/content/actions/list-documents.ts +3 -0
- package/corpus/templates/content/actions/pull-document.ts +2 -0
- package/corpus/templates/content/actions/search-documents.ts +5 -1
- package/corpus/templates/content/actions/update-document.ts +16 -1
- package/corpus/templates/content/actions/view-screen.ts +15 -2
- package/corpus/templates/content/app/components/editor/DescriptionField.tsx +121 -0
- package/corpus/templates/content/app/components/editor/DocumentEditor.tsx +14 -0
- package/corpus/templates/content/app/components/editor/DocumentProperties.tsx +223 -34
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +56 -8
- package/corpus/templates/content/app/i18n/zh-TW.ts +5 -0
- package/corpus/templates/content/app/i18n-data.ts +52 -0
- package/corpus/templates/content/changelog/2026-07-14-pages-and-databases-can-describe-themselves-with-guidance-fo.md +6 -0
- package/corpus/templates/content/changelog/2026-07-14-slack-follow-ups-now-retain-created-content-identity-and-per.md +6 -0
- package/corpus/templates/content/server/db/schema.ts +4 -0
- package/corpus/templates/content/server/lib/document-context.ts +76 -0
- package/corpus/templates/content/server/lib/public-documents.ts +3 -0
- package/corpus/templates/content/server/plugins/db.ts +6 -0
- package/corpus/templates/content/server/routes/api/document-agent-context.json.get.ts +5 -0
- package/corpus/templates/content/shared/api.ts +17 -0
- package/corpus/templates/content/shared/content-source.ts +7 -0
- package/corpus/templates/content/shared/properties.ts +2 -0
- package/dist/a2a/artifact-response.d.ts +15 -0
- package/dist/a2a/artifact-response.d.ts.map +1 -1
- package/dist/a2a/artifact-response.js +204 -5
- package/dist/a2a/artifact-response.js.map +1 -1
- package/dist/agent/thread-data-builder.d.ts +6 -0
- package/dist/agent/thread-data-builder.d.ts.map +1 -1
- package/dist/agent/thread-data-builder.js +71 -8
- package/dist/agent/thread-data-builder.js.map +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/integrations/a2a-continuation-processor.d.ts.map +1 -1
- package/dist/integrations/a2a-continuation-processor.js +72 -6
- package/dist/integrations/a2a-continuation-processor.js.map +1 -1
- package/dist/integrations/adapters/discord.d.ts.map +1 -1
- package/dist/integrations/adapters/discord.js +1 -0
- package/dist/integrations/adapters/discord.js.map +1 -1
- package/dist/integrations/adapters/email.d.ts.map +1 -1
- package/dist/integrations/adapters/email.js +2 -0
- package/dist/integrations/adapters/email.js.map +1 -1
- package/dist/integrations/adapters/google-docs.d.ts.map +1 -1
- package/dist/integrations/adapters/google-docs.js +2 -0
- package/dist/integrations/adapters/google-docs.js.map +1 -1
- package/dist/integrations/adapters/microsoft-teams.d.ts.map +1 -1
- package/dist/integrations/adapters/microsoft-teams.js +1 -0
- package/dist/integrations/adapters/microsoft-teams.js.map +1 -1
- package/dist/integrations/adapters/slack.d.ts.map +1 -1
- package/dist/integrations/adapters/slack.js +21 -6
- package/dist/integrations/adapters/slack.js.map +1 -1
- package/dist/integrations/adapters/telegram.d.ts.map +1 -1
- package/dist/integrations/adapters/telegram.js +11 -2
- package/dist/integrations/adapters/telegram.js.map +1 -1
- package/dist/integrations/adapters/whatsapp.d.ts.map +1 -1
- package/dist/integrations/adapters/whatsapp.js +3 -0
- package/dist/integrations/adapters/whatsapp.js.map +1 -1
- package/dist/integrations/index.d.ts +1 -1
- package/dist/integrations/index.d.ts.map +1 -1
- package/dist/integrations/index.js.map +1 -1
- package/dist/integrations/types.d.ts +8 -2
- package/dist/integrations/types.d.ts.map +1 -1
- package/dist/integrations/types.js.map +1 -1
- package/dist/integrations/webhook-handler.d.ts.map +1 -1
- package/dist/integrations/webhook-handler.js +40 -43
- package/dist/integrations/webhook-handler.js.map +1 -1
- package/dist/progress/routes.d.ts +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +2 -2
- package/dist/server/agent-chat/action-filters-a2a.d.ts.map +1 -1
- package/dist/server/agent-chat/action-filters-a2a.js +1 -0
- package/dist/server/agent-chat/action-filters-a2a.js.map +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/docs/content/locales/ar-SA/pure-agent-apps.mdx +2 -2
- package/docs/content/locales/de-DE/pure-agent-apps.mdx +2 -2
- package/docs/content/locales/es-ES/pure-agent-apps.mdx +2 -2
- package/docs/content/locales/fr-FR/pure-agent-apps.mdx +2 -2
- package/docs/content/locales/hi-IN/pure-agent-apps.mdx +2 -2
- package/docs/content/locales/ja-JP/pure-agent-apps.mdx +2 -2
- package/docs/content/locales/ko-KR/pure-agent-apps.mdx +2 -2
- package/docs/content/locales/pt-BR/pure-agent-apps.mdx +2 -2
- package/docs/content/locales/zh-CN/pure-agent-apps.mdx +2 -2
- package/docs/content/locales/zh-TW/pure-agent-apps.mdx +2 -2
- package/docs/content/pure-agent-apps.mdx +58 -14
- package/package.json +3 -3
|
@@ -495,14 +495,22 @@ mod macos {
|
|
|
495
495
|
let mut out = Vec::new();
|
|
496
496
|
for segment in state.as_iter() {
|
|
497
497
|
let text = segment.to_string();
|
|
498
|
-
if is_speech(&text)
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
498
|
+
if !is_speech(&text) || segment.no_speech_probability() >= MAX_NO_SPEECH_PROBABILITY {
|
|
499
|
+
continue;
|
|
500
|
+
}
|
|
501
|
+
// Low average token confidence means whisper was guessing —
|
|
502
|
+
// typically a mis-detected-language hallucination that reads
|
|
503
|
+
// fluently but scores poorly. Drop it.
|
|
504
|
+
let confidence = segment_confidence(&segment);
|
|
505
|
+
if confidence < MIN_AVG_TOKEN_PROBABILITY {
|
|
506
|
+
continue;
|
|
505
507
|
}
|
|
508
|
+
// whisper timestamps are in centiseconds → ms.
|
|
509
|
+
out.push((
|
|
510
|
+
segment.start_timestamp() * 10,
|
|
511
|
+
segment.end_timestamp() * 10,
|
|
512
|
+
text,
|
|
513
|
+
));
|
|
506
514
|
}
|
|
507
515
|
out
|
|
508
516
|
}
|
|
@@ -530,6 +538,40 @@ mod macos {
|
|
|
530
538
|
const VOICE_RMS_THRESHOLD: f32 = 0.006;
|
|
531
539
|
/// A second, model-level gate for ambient/no-speech Whisper segments.
|
|
532
540
|
const MAX_NO_SPEECH_PROBABILITY: f32 = 0.72;
|
|
541
|
+
/// Minimum average per-token probability for a segment to count as real
|
|
542
|
+
/// speech. On noisy/near-silent audio whisper mis-detects the language and
|
|
543
|
+
/// decodes fluent-looking gibberish in another language — but those tokens
|
|
544
|
+
/// are low-confidence under the hood. Dropping segments below this cutoff
|
|
545
|
+
/// removes that wrong-language garbage while keeping genuine multilingual
|
|
546
|
+
/// speech (which decodes with high confidence).
|
|
547
|
+
const MIN_AVG_TOKEN_PROBABILITY: f32 = 0.55;
|
|
548
|
+
|
|
549
|
+
/// Average the model's per-token probability across a segment. Returns 0.0
|
|
550
|
+
/// for an empty segment so it is treated as low-confidence. Special tokens
|
|
551
|
+
/// (timestamps, `[_BEG_]`, …) render as `[_…]` and are skipped so they
|
|
552
|
+
/// don't skew the average toward the text tokens we actually care about.
|
|
553
|
+
fn segment_confidence(segment: &whisper_rs::WhisperSegment<'_>) -> f32 {
|
|
554
|
+
let mut sum = 0.0f32;
|
|
555
|
+
let mut count = 0u32;
|
|
556
|
+
for i in 0..segment.n_tokens() {
|
|
557
|
+
let Some(token) = segment.get_token(i) else {
|
|
558
|
+
continue;
|
|
559
|
+
};
|
|
560
|
+
let is_special = token
|
|
561
|
+
.to_str_lossy()
|
|
562
|
+
.map(|t| t.starts_with("[_"))
|
|
563
|
+
.unwrap_or(false);
|
|
564
|
+
if is_special {
|
|
565
|
+
continue;
|
|
566
|
+
}
|
|
567
|
+
sum += token.token_probability();
|
|
568
|
+
count += 1;
|
|
569
|
+
}
|
|
570
|
+
if count == 0 {
|
|
571
|
+
return 0.0;
|
|
572
|
+
}
|
|
573
|
+
sum / count as f32
|
|
574
|
+
}
|
|
533
575
|
|
|
534
576
|
fn partial_inference_due(
|
|
535
577
|
emit_partials: bool,
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
getRequestOrgId,
|
|
7
7
|
} from "@agent-native/core/server/request-context";
|
|
8
8
|
import { and, desc, eq, sql } from "drizzle-orm";
|
|
9
|
-
import type
|
|
9
|
+
import { HTTPError, type H3Event } from "h3";
|
|
10
10
|
|
|
11
11
|
import { getDb, schema } from "../db/index.js";
|
|
12
12
|
|
|
@@ -120,7 +120,10 @@ export async function requireOrganizationAccess(
|
|
|
120
120
|
const email = getCurrentOwnerEmail();
|
|
121
121
|
const role = await getOrganizationRoleForEmail(resolvedOrganizationId, email);
|
|
122
122
|
if (!role || !organizationRoleAllowed(role, allowedRoles)) {
|
|
123
|
-
throw new
|
|
123
|
+
throw new HTTPError({
|
|
124
|
+
statusCode: 403,
|
|
125
|
+
statusMessage: "Organization not found or access denied",
|
|
126
|
+
});
|
|
124
127
|
}
|
|
125
128
|
return { organizationId: resolvedOrganizationId, email, role };
|
|
126
129
|
}
|
|
@@ -101,6 +101,37 @@ inferences for confirmation, then submit once. When required information is
|
|
|
101
101
|
missing, keep the clarification in the originating thread and retain earlier
|
|
102
102
|
answers as context.
|
|
103
103
|
|
|
104
|
+
### Slack Follow-ups And Corrections
|
|
105
|
+
|
|
106
|
+
A follow-up in an existing Slack thread is not automatically a new intake. Read
|
|
107
|
+
the thread context and inspect the prior Content artifact identity first,
|
|
108
|
+
including any returned document ID or `/page/<id>` path and the canonical
|
|
109
|
+
database row when available. Then choose the operation that matches the user's
|
|
110
|
+
intent:
|
|
111
|
+
|
|
112
|
+
- **Update** the same document for corrections, refinements, status changes, or
|
|
113
|
+
renames that still describe the same request. A rename changes the title, not
|
|
114
|
+
the artifact identity: preserve the stable Content document ID and page path.
|
|
115
|
+
- **Add** new details to the same document when the follow-up extends the
|
|
116
|
+
original request without replacing it.
|
|
117
|
+
- **Supersede** only when the user intends a replacement artifact or distinct
|
|
118
|
+
successor and the workspace's schema or instructions define how that
|
|
119
|
+
relationship is recorded. Preserve a concrete link to the prior artifact.
|
|
120
|
+
- **Create** only when the follow-up is genuinely a separate request or the user
|
|
121
|
+
explicitly asks for a new artifact. Do not blindly submit another row merely
|
|
122
|
+
because a new Slack message arrived.
|
|
123
|
+
|
|
124
|
+
Apply people fields from verified identity and intent, not from convenient
|
|
125
|
+
guesswork:
|
|
126
|
+
|
|
127
|
+
- When the database has a `Requester` field, default it to the verified Slack
|
|
128
|
+
sender unless the user explicitly identifies a different requester.
|
|
129
|
+
- A named doer such as "for Apoorva" maps to `Assignee` when that field exists.
|
|
130
|
+
Naming an assignee never changes or replaces `Requester`.
|
|
131
|
+
- Resolve named people to the database's accepted person identity before
|
|
132
|
+
writing. If a named person cannot be resolved unambiguously, clarify in the
|
|
133
|
+
originating Slack thread; never omit, downgrade, or silently drop the person.
|
|
134
|
+
|
|
104
135
|
## Local File Mode
|
|
105
136
|
|
|
106
137
|
Install into an existing repo with:
|
|
@@ -7,7 +7,10 @@ description: >-
|
|
|
7
7
|
|
|
8
8
|
# Document Editing
|
|
9
9
|
|
|
10
|
-
Documents are stored in the SQL database via Drizzle ORM. Each document has a
|
|
10
|
+
Documents are stored in the SQL database via Drizzle ORM. Each document has a
|
|
11
|
+
title, stable description, markdown content, optional parent (for nesting), and
|
|
12
|
+
a position for ordering. The description explains why the page exists and what
|
|
13
|
+
belongs there; it is not a changing synopsis of the current body.
|
|
11
14
|
|
|
12
15
|
## Scripts
|
|
13
16
|
|
|
@@ -48,6 +51,7 @@ Create a new document.
|
|
|
48
51
|
pnpm action create-document --title "Meeting Notes" --content "# Meeting Notes\n\nAttendees: ..."
|
|
49
52
|
pnpm action create-document --title "Sub Page" --parentId parent123
|
|
50
53
|
pnpm action create-document --title "My Page" --icon "📝"
|
|
54
|
+
pnpm action create-document --title "Research" --description "Evidence and source notes that support the current project"
|
|
51
55
|
```
|
|
52
56
|
|
|
53
57
|
### edit-document
|
|
@@ -73,6 +77,7 @@ Update an existing document. Use for **full rewrites or new content**, not for s
|
|
|
73
77
|
pnpm action update-document --id abc123 --title "New Title"
|
|
74
78
|
pnpm action update-document --id abc123 --content "# Updated Content\n\nNew text here"
|
|
75
79
|
pnpm action update-document --id abc123 --title "New Title" --content "New content"
|
|
80
|
+
pnpm action update-document --id abc123 --description "Stable guidance for what belongs on this page"
|
|
76
81
|
```
|
|
77
82
|
|
|
78
83
|
### delete-document
|
|
@@ -123,17 +128,18 @@ Always run this after any document modification to update the sidebar.
|
|
|
123
128
|
|
|
124
129
|
## Document Schema
|
|
125
130
|
|
|
126
|
-
| Column
|
|
127
|
-
|
|
|
128
|
-
| `id`
|
|
129
|
-
| `parent_id`
|
|
130
|
-
| `title`
|
|
131
|
-
| `
|
|
132
|
-
| `
|
|
133
|
-
| `
|
|
134
|
-
| `
|
|
135
|
-
| `
|
|
136
|
-
| `
|
|
131
|
+
| Column | Type | Description |
|
|
132
|
+
| ------------- | ------- | -------------------------------------- |
|
|
133
|
+
| `id` | text | Primary key (12-char hex string) |
|
|
134
|
+
| `parent_id` | text | Parent document ID (null for root) |
|
|
135
|
+
| `title` | text | Document title (default: "Untitled") |
|
|
136
|
+
| `description` | text | Stable semantic guidance for the page |
|
|
137
|
+
| `content` | text | Markdown content |
|
|
138
|
+
| `icon` | text | Emoji icon (optional) |
|
|
139
|
+
| `position` | integer | Sort order within parent (0-based) |
|
|
140
|
+
| `is_favorite` | integer | Whether document is favorited (0 or 1) |
|
|
141
|
+
| `created_at` | text | ISO timestamp |
|
|
142
|
+
| `updated_at` | text | ISO timestamp |
|
|
137
143
|
|
|
138
144
|
## Content Format
|
|
139
145
|
|
|
@@ -142,21 +148,29 @@ Documents use **markdown** for content. The editor renders markdown in real time
|
|
|
142
148
|
## Parent-Child Hierarchy
|
|
143
149
|
|
|
144
150
|
Documents form a tree via `parent_id`:
|
|
151
|
+
|
|
145
152
|
- Root documents have `parent_id = null`
|
|
146
153
|
- Child documents reference their parent's `id`
|
|
147
154
|
- Deleting a parent recursively deletes all children
|
|
148
155
|
- Position determines ordering within the same parent
|
|
149
156
|
|
|
157
|
+
Descriptions are owned; context is inherited. `get-document` and `view-screen`
|
|
158
|
+
return the focused page's own description plus a computed root-to-parent
|
|
159
|
+
`contextPath`. Use that path to understand where the page lives, but never copy
|
|
160
|
+
ancestor descriptions into the child. Database, property, and option
|
|
161
|
+
descriptions narrow the guidance further when working with structured values.
|
|
162
|
+
|
|
150
163
|
## Common Tasks
|
|
151
164
|
|
|
152
|
-
| User says
|
|
153
|
-
|
|
|
154
|
-
| "Create a page about X"
|
|
155
|
-
| "
|
|
156
|
-
| "
|
|
157
|
-
| "
|
|
158
|
-
| "
|
|
159
|
-
| "
|
|
160
|
-
| "
|
|
165
|
+
| User says | What to do |
|
|
166
|
+
| ---------------------------- | ----------------------------------------------------------------------------------- |
|
|
167
|
+
| "Create a page about X" | `create-document --title "X" --content "# X\n\n..."` |
|
|
168
|
+
| "Describe what belongs here" | `update-document --id ... --description "..."` |
|
|
169
|
+
| "Find my meeting notes" | `search-documents --query "meeting notes"` |
|
|
170
|
+
| "Fix a typo / edit a line" | `view-screen` to get ID, then `edit-document --id ... --find "old" --replace "new"` |
|
|
171
|
+
| "Rewrite this document" | `view-screen` to get ID, then `update-document --id ... --content ...` |
|
|
172
|
+
| "Delete this page" | `view-screen` to get ID, then `delete-document --id ...` |
|
|
173
|
+
| "Add a sub-page" | `create-document --title "Sub" --parentId <parentId>` |
|
|
174
|
+
| "Show me the document tree" | `list-documents` |
|
|
161
175
|
|
|
162
176
|
Always run `refresh-list` after any create, update, or delete operation.
|
|
@@ -102,19 +102,19 @@ cd templates/content && pnpm action <name> [args]
|
|
|
102
102
|
| `push-builder-doc` | `--files <json> [--path <file.builder.mdx>] [--dryRun true\|false]` | Guarded Builder autosave PATCH for the safe Builder test model; never publishes |
|
|
103
103
|
| `navigate` | `--path <path>` or `--documentId <id>` or `--databaseId <id>` | Open a route, document page, or database page in the UI |
|
|
104
104
|
| `search-documents` | `--query <text> [--format json]` | Search by title/content and return snippets |
|
|
105
|
-
| `get-document` | `--id <id> [--format json]` | Get a
|
|
105
|
+
| `get-document` | `--id <id> [--format json]` | Get a document with content, stable description, properties, and computed ancestry context |
|
|
106
106
|
| `pull-document` | `--id <id> [--format markdown\|text]` | Collab-aware "ingest the final" read |
|
|
107
|
-
| `create-document` | `--title <text> [--content] [--parentId] [--icon]`
|
|
107
|
+
| `create-document` | `--title <text> [--content] [--description] [--parentId] [--icon]` | Create a document with optional stable guidance about why it exists and what belongs there |
|
|
108
108
|
| `edit-document` | `--id <id> --find <text> --replace <text>` | Surgical text edit (preferred for modifications) |
|
|
109
109
|
| `edit-document` | `--id <id> --edits <json>` | Batch surgical text edits |
|
|
110
|
-
| `update-document` | `--id <id> [--title] [--content] [--icon]`
|
|
110
|
+
| `update-document` | `--id <id> [--title] [--content] [--description] [--icon]` | Update document fields; descriptions are stable guidance, not summaries of current content |
|
|
111
111
|
| `share-local-file-document` | `--id <local-file-document-id>` | Create or refresh a DB-backed shareable copy of a local file document |
|
|
112
112
|
| `remove-local-file-source` | `[--sourceRootPath <path>]` | Unlink local-file sources from Content without deleting local Markdown/MDX files |
|
|
113
113
|
| `list-local-component-files` | | List registered local MDX component source files |
|
|
114
114
|
| `write-local-component-file` | `--workspaceId <id> --path <relative-component-path> --content <source>` | Create or update a file in a registered local `components/` folder |
|
|
115
|
-
| `create-content-database` | `[--documentId <id>] [--parentId <id>] [--title <text>]`
|
|
116
|
-
| `create-inline-content-database` | `--hostDocumentId <id> [--title <text>]`
|
|
117
|
-
| `get-content-database` | `--databaseId <id>` or `--documentId <id>` | Get a database
|
|
115
|
+
| `create-content-database` | `[--documentId <id>] [--parentId <id>] [--title <text>] [--description <text>]` | Create a described database page or convert an existing page into a database |
|
|
116
|
+
| `create-inline-content-database` | `--hostDocumentId <id> [--title <text>] [--description <text>]` | Create a described database owned by an inline database block in the host document |
|
|
117
|
+
| `get-content-database` | `--databaseId <id>` or `--documentId <id>` | Get a database with its description, property/option schema guidance, item pages, and computed ancestry context |
|
|
118
118
|
| `list-trashed-content-databases` | | List soft-deleted databases visible in the sidebar Trash surface |
|
|
119
119
|
| `restore-content-database` | `--databaseId <id>` | Restore a soft-deleted database from the sidebar Trash surface |
|
|
120
120
|
| `get-content-database-source` | `--databaseId <id>` or `--documentId <id>` | Inspect local/no-source or source-backed status, mappings, row identity, freshness, and change sets |
|
|
@@ -138,7 +138,7 @@ cd templates/content && pnpm action <name> [args]
|
|
|
138
138
|
| `move-database-item` | `--itemId <id>` or `--documentId <id> --position <number>` | Move a database row page to a new zero-based table position |
|
|
139
139
|
| `update-content-database-view` | `--databaseId <id> --viewConfig <json>` | Persist database views, sorts, filters, hidden properties, and view settings |
|
|
140
140
|
| `list-document-properties` | `--documentId <id> [--format json]` | List Notion-style property definitions and values for a document |
|
|
141
|
-
| `configure-document-property` | `--documentId <id> [--id <propertyId>] --name <name> --type <type> [--visibility always_show\|hide_when_empty\|always_hide]`
|
|
141
|
+
| `configure-document-property` | `--documentId <id> [--id <propertyId>] --name <name> --type <type> [--description <text>] [--visibility always_show\|hide_when_empty\|always_hide] [--options <json>]` | Create or update a property definition and its option-level guidance |
|
|
142
142
|
| `duplicate-document-property` | `--documentId <id> --propertyId <propertyId>` | Duplicate a property definition and its stored values |
|
|
143
143
|
| `delete-document-property` | `--documentId <id> --propertyId <propertyId>` | Delete a property definition and its stored values |
|
|
144
144
|
| `set-document-property` | `--documentId <id> --propertyId <propertyId> --value <json>` | Set a document property value (for a `blocks` field, the value is its markdown content) |
|
|
@@ -151,6 +151,27 @@ Database views follow Notion-style tab labels. When creating or duplicating
|
|
|
151
151
|
views in `viewConfig`, use unique default names (`Table 2`, `SEO copy 2`, etc.)
|
|
152
152
|
instead of appending several tabs with the same label.
|
|
153
153
|
|
|
154
|
+
### Self-Documenting Descriptions
|
|
155
|
+
|
|
156
|
+
Descriptions are stable semantic guidance, not generated summaries of current
|
|
157
|
+
content. Preserve this distinction when reading or writing them:
|
|
158
|
+
|
|
159
|
+
- A page description explains why the page exists and what belongs there.
|
|
160
|
+
- A database description explains the collection's purpose and inclusion
|
|
161
|
+
boundary. Inline and full-page views of one database share the same
|
|
162
|
+
description.
|
|
163
|
+
- A property description explains what the field means and what value belongs
|
|
164
|
+
there.
|
|
165
|
+
- A select, status, or multi-select option description explains when to choose
|
|
166
|
+
that option.
|
|
167
|
+
|
|
168
|
+
Descriptions are owned; context is inherited. Never copy an ancestor's prose
|
|
169
|
+
into a child description. Focused reads expose a root-to-parent `contextPath`
|
|
170
|
+
so the agent can use ancestor guidance without creating stale duplicates. Read
|
|
171
|
+
the returned descriptions before placing content or setting property values.
|
|
172
|
+
Update a description only when the object's meaning changes, not whenever its
|
|
173
|
+
current content changes.
|
|
174
|
+
|
|
154
175
|
**`pull-document` is the collab-aware "ingest the final" read** — prefer it over
|
|
155
176
|
`get-document` for external ingest (another app, an external coding agent over
|
|
156
177
|
MCP/A2A, an A2A peer). `get-document` returns whatever is in the
|
|
@@ -388,6 +409,7 @@ Public documents are reachable at `/p/<id>` once visibility is `public`. Anyone
|
|
|
388
409
|
| ------------------------------ | ------------------------------------------------------------------------------ |
|
|
389
410
|
| "What am I looking at?" | `view-screen` |
|
|
390
411
|
| "Create a page about X" | `create-document --title "X" --content "# X\n\n..."` |
|
|
412
|
+
| "Explain what belongs here" | `view-screen` to get ID, `update-document --id ... --description "..."` |
|
|
391
413
|
| "Find my meeting notes" | `search-documents --query "meeting notes"` |
|
|
392
414
|
| "Update the title of this doc" | `view-screen` to get ID, `update-document --id ... --title "New"` |
|
|
393
415
|
| "Fix a typo / small edit" | `view-screen` to get ID, `edit-document --id ... --find "old" --replace "new"` |
|
|
@@ -49,6 +49,7 @@ import {
|
|
|
49
49
|
parsePropertyOptions,
|
|
50
50
|
serializePropertyOptions,
|
|
51
51
|
serializePropertyValue,
|
|
52
|
+
type DocumentPropertyOption,
|
|
52
53
|
type DocumentPropertyOptionColor,
|
|
53
54
|
} from "../shared/properties.js";
|
|
54
55
|
import { sanitizeNormalizationFormula } from "../shared/properties.js";
|
|
@@ -5193,6 +5194,34 @@ const SOURCE_OPTION_PALETTE: DocumentPropertyOptionColor[] = [
|
|
|
5193
5194
|
"red",
|
|
5194
5195
|
];
|
|
5195
5196
|
|
|
5197
|
+
export function sourcePropertyOptionsForSources(
|
|
5198
|
+
sources: Array<{ id: string; sourceName: string }>,
|
|
5199
|
+
priorOptions: DocumentPropertyOption[],
|
|
5200
|
+
) {
|
|
5201
|
+
const priorById = new Map(priorOptions.map((option) => [option.id, option]));
|
|
5202
|
+
const retainDescription = (id: string) => {
|
|
5203
|
+
const description = priorById.get(id)?.description;
|
|
5204
|
+
return description ? { description } : {};
|
|
5205
|
+
};
|
|
5206
|
+
return [
|
|
5207
|
+
...sources.map((source, index) => ({
|
|
5208
|
+
id: source.id,
|
|
5209
|
+
name: source.sourceName,
|
|
5210
|
+
color:
|
|
5211
|
+
priorById.get(source.id)?.color ??
|
|
5212
|
+
SOURCE_OPTION_PALETTE[index % SOURCE_OPTION_PALETTE.length],
|
|
5213
|
+
...retainDescription(source.id),
|
|
5214
|
+
})),
|
|
5215
|
+
{
|
|
5216
|
+
id: SOURCE_LOCAL_OPTION_ID,
|
|
5217
|
+
name: "Local",
|
|
5218
|
+
color: (priorById.get(SOURCE_LOCAL_OPTION_ID)?.color ??
|
|
5219
|
+
"gray") as DocumentPropertyOptionColor,
|
|
5220
|
+
...retainDescription(SOURCE_LOCAL_OPTION_ID),
|
|
5221
|
+
},
|
|
5222
|
+
];
|
|
5223
|
+
}
|
|
5224
|
+
|
|
5196
5225
|
/**
|
|
5197
5226
|
* Ensure a "Source" select property exists tagging each row with the collection
|
|
5198
5227
|
* it belongs to, and (re)set every item's value. Rows with no source binding are
|
|
@@ -5233,22 +5262,7 @@ export async function ensureDatabaseSourceProperty(args: {
|
|
|
5233
5262
|
// that can't collide with a UUID source id). Resolving a row's tag back to a
|
|
5234
5263
|
// source is then pure id matching — no source-name hop — so duplicate display
|
|
5235
5264
|
// names or a collection literally named "Local" can never misroute a row.
|
|
5236
|
-
const
|
|
5237
|
-
const options = [
|
|
5238
|
-
...sources.map((source, index) => ({
|
|
5239
|
-
id: source.id,
|
|
5240
|
-
name: source.sourceName,
|
|
5241
|
-
color:
|
|
5242
|
-
priorById.get(source.id)?.color ??
|
|
5243
|
-
SOURCE_OPTION_PALETTE[index % SOURCE_OPTION_PALETTE.length],
|
|
5244
|
-
})),
|
|
5245
|
-
{
|
|
5246
|
-
id: SOURCE_LOCAL_OPTION_ID,
|
|
5247
|
-
name: "Local",
|
|
5248
|
-
color: (priorById.get(SOURCE_LOCAL_OPTION_ID)?.color ??
|
|
5249
|
-
"gray") as DocumentPropertyOptionColor,
|
|
5250
|
-
},
|
|
5251
|
-
];
|
|
5265
|
+
const options = sourcePropertyOptionsForSources(sources, priorOptions);
|
|
5252
5266
|
const optionsJson = serializePropertyOptions({ options });
|
|
5253
5267
|
|
|
5254
5268
|
let propertyId: string;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { and, asc, eq, inArray, isNull, sql } from "drizzle-orm";
|
|
2
2
|
|
|
3
3
|
import { getDb, schema } from "../server/db/index.js";
|
|
4
|
+
import { getDocumentContextPath } from "../server/lib/document-context.js";
|
|
4
5
|
import {
|
|
5
6
|
parseDocumentFavorite,
|
|
6
7
|
parseDocumentHideFromSearch,
|
|
@@ -20,6 +21,7 @@ import {
|
|
|
20
21
|
listPropertiesForDatabase,
|
|
21
22
|
serializeDatabase,
|
|
22
23
|
} from "./_property-utils.js";
|
|
24
|
+
export { getDocumentContextPath };
|
|
23
25
|
|
|
24
26
|
export const CONTENT_DATABASE_MAX_READ_LIMIT = 5_000;
|
|
25
27
|
|
|
@@ -131,6 +133,7 @@ function serializeDocument(
|
|
|
131
133
|
parentId: doc.parentId,
|
|
132
134
|
title: doc.title,
|
|
133
135
|
content: options.includeContent === true ? doc.content : "",
|
|
136
|
+
description: doc.description,
|
|
134
137
|
icon: doc.icon,
|
|
135
138
|
position: doc.position,
|
|
136
139
|
isFavorite: parseDocumentFavorite(doc.isFavorite),
|
|
@@ -160,6 +163,14 @@ export async function getContentDatabaseResponse(
|
|
|
160
163
|
if (!database || database.deletedAt) {
|
|
161
164
|
throw new Error(`Database "${databaseId}" not found`);
|
|
162
165
|
}
|
|
166
|
+
const [databaseDocument] = await db
|
|
167
|
+
.select({
|
|
168
|
+
id: schema.documents.id,
|
|
169
|
+
parentId: schema.documents.parentId,
|
|
170
|
+
description: schema.documents.description,
|
|
171
|
+
})
|
|
172
|
+
.from(schema.documents)
|
|
173
|
+
.where(eq(schema.documents.id, database.documentId));
|
|
163
174
|
|
|
164
175
|
// PURE read: the primary "Content" Blocks field is seeded at create time and
|
|
165
176
|
// by the one-time startup repair — never here. Reading a database (including a
|
|
@@ -272,7 +283,10 @@ export async function getContentDatabaseResponse(
|
|
|
272
283
|
const itemsWithOverlay = applyFederatedOverlayValues(federatedItems);
|
|
273
284
|
|
|
274
285
|
return {
|
|
275
|
-
database: serializeDatabase(database),
|
|
286
|
+
database: serializeDatabase(database, databaseDocument?.description ?? ""),
|
|
287
|
+
contextPath: databaseDocument
|
|
288
|
+
? await getDocumentContextPath(databaseDocument)
|
|
289
|
+
: [],
|
|
276
290
|
properties: await listPropertiesForDatabase(databaseId),
|
|
277
291
|
items: itemsWithOverlay,
|
|
278
292
|
source: pagedPrimary,
|
|
@@ -154,6 +154,7 @@ function documentFromFolder(folderPath: string, position: number): Document {
|
|
|
154
154
|
parentId: folderParentId(folderPath),
|
|
155
155
|
title: titleFromSegment(basename(folderPath)),
|
|
156
156
|
content: "",
|
|
157
|
+
description: "",
|
|
157
158
|
icon: null,
|
|
158
159
|
position,
|
|
159
160
|
isFavorite: false,
|
|
@@ -189,6 +190,7 @@ function documentFromLocalFile(
|
|
|
189
190
|
parentId: parentFolderId(file.path),
|
|
190
191
|
title: parsed.title,
|
|
191
192
|
content: parsed.content,
|
|
193
|
+
description: parsed.description ?? "",
|
|
192
194
|
icon: parsed.icon ?? null,
|
|
193
195
|
position,
|
|
194
196
|
isFavorite: parsed.isFavorite ?? false,
|
|
@@ -410,6 +412,33 @@ export async function getLocalFileDocument(id: string): Promise<Document> {
|
|
|
410
412
|
return documentFromLocalFile(file, file.content, 0);
|
|
411
413
|
}
|
|
412
414
|
|
|
415
|
+
export async function getLocalDocumentContextPath(id: string) {
|
|
416
|
+
const documents = await listLocalFileDocuments();
|
|
417
|
+
const byId = new Map(documents.map((document) => [document.id, document]));
|
|
418
|
+
const current = byId.get(id) ?? (await getLocalFileDocument(id));
|
|
419
|
+
const path: Array<{
|
|
420
|
+
id: string;
|
|
421
|
+
kind: "page" | "database";
|
|
422
|
+
title: string;
|
|
423
|
+
description: string;
|
|
424
|
+
}> = [];
|
|
425
|
+
const seen = new Set([current.id]);
|
|
426
|
+
let parentId = current.parentId;
|
|
427
|
+
while (parentId && !seen.has(parentId)) {
|
|
428
|
+
seen.add(parentId);
|
|
429
|
+
const parent = byId.get(parentId);
|
|
430
|
+
if (!parent) break;
|
|
431
|
+
path.unshift({
|
|
432
|
+
id: parent.id,
|
|
433
|
+
kind: "page",
|
|
434
|
+
title: parent.title,
|
|
435
|
+
description: parent.description ?? "",
|
|
436
|
+
});
|
|
437
|
+
parentId = parent.parentId;
|
|
438
|
+
}
|
|
439
|
+
return path;
|
|
440
|
+
}
|
|
441
|
+
|
|
413
442
|
function splitFrontmatter(source: string) {
|
|
414
443
|
const match = source.match(FRONTMATTER_RE);
|
|
415
444
|
if (!match) return { frontmatter: "", body: source };
|
|
@@ -517,12 +546,16 @@ function updateFrontmatterFields(
|
|
|
517
546
|
titleChanged: boolean,
|
|
518
547
|
iconChanged: boolean,
|
|
519
548
|
favoriteChanged: boolean,
|
|
549
|
+
descriptionChanged: boolean,
|
|
520
550
|
) {
|
|
521
551
|
if (usesDocsNoBookkeepingProfile(file.profile)) {
|
|
522
552
|
return {
|
|
523
553
|
...(titleChanged ? { title: nextTitle || "Untitled" } : {}),
|
|
524
554
|
...(iconChanged ? { icon: args.icon ?? null } : {}),
|
|
525
555
|
...(favoriteChanged ? { isFavorite: args.isFavorite ?? false } : {}),
|
|
556
|
+
...(descriptionChanged
|
|
557
|
+
? { description: args.description?.trim() ?? "" }
|
|
558
|
+
: {}),
|
|
526
559
|
};
|
|
527
560
|
}
|
|
528
561
|
|
|
@@ -531,6 +564,10 @@ function updateFrontmatterFields(
|
|
|
531
564
|
icon: args.icon !== undefined ? args.icon : current.icon,
|
|
532
565
|
isFavorite:
|
|
533
566
|
args.isFavorite !== undefined ? args.isFavorite : current.isFavorite,
|
|
567
|
+
description:
|
|
568
|
+
args.description !== undefined
|
|
569
|
+
? args.description.trim()
|
|
570
|
+
: current.description,
|
|
534
571
|
updatedAt: new Date().toISOString(),
|
|
535
572
|
};
|
|
536
573
|
}
|
|
@@ -544,6 +581,9 @@ function createFrontmatterFields(
|
|
|
544
581
|
return {
|
|
545
582
|
title,
|
|
546
583
|
...(args.icon !== undefined ? { icon: args.icon || null } : {}),
|
|
584
|
+
...(args.description !== undefined
|
|
585
|
+
? { description: args.description.trim() }
|
|
586
|
+
: {}),
|
|
547
587
|
};
|
|
548
588
|
}
|
|
549
589
|
|
|
@@ -551,6 +591,7 @@ function createFrontmatterFields(
|
|
|
551
591
|
title,
|
|
552
592
|
icon: args.icon || null,
|
|
553
593
|
isFavorite: false,
|
|
594
|
+
description: args.description?.trim() ?? "",
|
|
554
595
|
updatedAt: new Date().toISOString(),
|
|
555
596
|
};
|
|
556
597
|
}
|
|
@@ -576,8 +617,17 @@ export async function updateLocalFileDocument(
|
|
|
576
617
|
const iconChanged = args.icon !== undefined && args.icon !== current.icon;
|
|
577
618
|
const favoriteChanged =
|
|
578
619
|
args.isFavorite !== undefined && args.isFavorite !== current.isFavorite;
|
|
620
|
+
const descriptionChanged =
|
|
621
|
+
args.description !== undefined &&
|
|
622
|
+
args.description.trim() !== current.description;
|
|
579
623
|
|
|
580
|
-
if (
|
|
624
|
+
if (
|
|
625
|
+
!titleChanged &&
|
|
626
|
+
!contentChanged &&
|
|
627
|
+
!iconChanged &&
|
|
628
|
+
!favoriteChanged &&
|
|
629
|
+
!descriptionChanged
|
|
630
|
+
) {
|
|
581
631
|
return current;
|
|
582
632
|
}
|
|
583
633
|
|
|
@@ -591,6 +641,7 @@ export async function updateLocalFileDocument(
|
|
|
591
641
|
titleChanged,
|
|
592
642
|
iconChanged,
|
|
593
643
|
favoriteChanged,
|
|
644
|
+
descriptionChanged,
|
|
594
645
|
),
|
|
595
646
|
nextContent,
|
|
596
647
|
);
|
|
@@ -712,6 +763,7 @@ export async function localContentViewScreenSummary() {
|
|
|
712
763
|
id: document.id,
|
|
713
764
|
parentId: document.parentId,
|
|
714
765
|
title: document.title,
|
|
766
|
+
description: document.description,
|
|
715
767
|
source: document.source,
|
|
716
768
|
})),
|
|
717
769
|
};
|
|
@@ -151,11 +151,15 @@ export async function getDatabaseById(
|
|
|
151
151
|
return database ?? null;
|
|
152
152
|
}
|
|
153
153
|
|
|
154
|
-
export function serializeDatabase(
|
|
154
|
+
export function serializeDatabase(
|
|
155
|
+
database: ContentDatabaseRow,
|
|
156
|
+
description = "",
|
|
157
|
+
) {
|
|
155
158
|
return {
|
|
156
159
|
id: database.id,
|
|
157
160
|
documentId: database.documentId,
|
|
158
161
|
title: database.title,
|
|
162
|
+
description,
|
|
159
163
|
viewConfig: parseDatabaseViewConfig(database.viewConfigJson),
|
|
160
164
|
createdAt: database.createdAt,
|
|
161
165
|
updatedAt: database.updatedAt,
|
|
@@ -500,6 +504,7 @@ export async function listPropertiesForDatabase(
|
|
|
500
504
|
databaseId: definition.databaseId,
|
|
501
505
|
name: definition.name,
|
|
502
506
|
type,
|
|
507
|
+
description: definition.description,
|
|
503
508
|
visibility: normalizePropertyVisibility(definition.visibility),
|
|
504
509
|
options,
|
|
505
510
|
position: definition.position,
|
|
@@ -568,6 +573,7 @@ function serializePropertyDefinition(
|
|
|
568
573
|
databaseId: definition.databaseId,
|
|
569
574
|
name: definition.name,
|
|
570
575
|
type,
|
|
576
|
+
description: definition.description,
|
|
571
577
|
visibility: normalizePropertyVisibility(definition.visibility),
|
|
572
578
|
options: parsePropertyOptions(definition.optionsJson),
|
|
573
579
|
position: definition.position,
|
|
@@ -36,6 +36,12 @@ export default defineAction({
|
|
|
36
36
|
.string()
|
|
37
37
|
.describe("Document ID used to scope the property workspace"),
|
|
38
38
|
name: z.string().min(1).describe("Property name"),
|
|
39
|
+
description: z
|
|
40
|
+
.string()
|
|
41
|
+
.optional()
|
|
42
|
+
.describe(
|
|
43
|
+
"Stable guidance describing what this property means and which value belongs here",
|
|
44
|
+
),
|
|
39
45
|
type: z.enum(CREATABLE_DOCUMENT_PROPERTY_TYPES).describe("Property type"),
|
|
40
46
|
visibility: z
|
|
41
47
|
.enum(DOCUMENT_PROPERTY_VISIBILITIES)
|
|
@@ -49,6 +55,7 @@ export default defineAction({
|
|
|
49
55
|
id: z.string(),
|
|
50
56
|
name: z.string(),
|
|
51
57
|
color: z.string(),
|
|
58
|
+
description: z.string().optional(),
|
|
52
59
|
}),
|
|
53
60
|
)
|
|
54
61
|
.optional(),
|
|
@@ -162,6 +169,9 @@ export default defineAction({
|
|
|
162
169
|
.update(schema.documentPropertyDefinitions)
|
|
163
170
|
.set({
|
|
164
171
|
name,
|
|
172
|
+
...(args.description === undefined
|
|
173
|
+
? {}
|
|
174
|
+
: { description: args.description.trim() }),
|
|
165
175
|
type,
|
|
166
176
|
visibility:
|
|
167
177
|
args.visibility === undefined
|
|
@@ -196,6 +206,7 @@ export default defineAction({
|
|
|
196
206
|
orgId: document.orgId ?? null,
|
|
197
207
|
databaseId: database.id,
|
|
198
208
|
name,
|
|
209
|
+
description: args.description?.trim() ?? "",
|
|
199
210
|
type,
|
|
200
211
|
visibility: normalizePropertyVisibility(args.visibility),
|
|
201
212
|
optionsJson,
|