@agent-native/core 0.101.6 → 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/corpus/README.md +1 -1
- package/corpus/core/CHANGELOG.md +6 -0
- 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/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/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/observability/routes.d.ts +1 -1
- package/dist/provider-api/corpus-jobs.d.ts +2 -2
- package/dist/resources/handlers.d.ts +1 -1
- 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/package.json +1 -1
|
@@ -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,
|
|
@@ -28,6 +28,10 @@ const createContentDatabaseSchema = z.object({
|
|
|
28
28
|
.nullish()
|
|
29
29
|
.describe("Parent document for a new database page"),
|
|
30
30
|
title: z.string().optional().describe("Database title"),
|
|
31
|
+
description: z
|
|
32
|
+
.string()
|
|
33
|
+
.optional()
|
|
34
|
+
.describe("Stable guidance describing what belongs in this database"),
|
|
31
35
|
});
|
|
32
36
|
|
|
33
37
|
export default defineAction({
|
|
@@ -110,6 +114,12 @@ export async function createContentDatabaseRecord(
|
|
|
110
114
|
.set({ title, updatedAt: now })
|
|
111
115
|
.where(eq(schema.documents.id, documentId));
|
|
112
116
|
}
|
|
117
|
+
if (args.description !== undefined) {
|
|
118
|
+
await db
|
|
119
|
+
.update(schema.documents)
|
|
120
|
+
.set({ description: args.description.trim(), updatedAt: now })
|
|
121
|
+
.where(eq(schema.documents.id, documentId));
|
|
122
|
+
}
|
|
113
123
|
} else {
|
|
114
124
|
title = databaseTitleForPage(title);
|
|
115
125
|
const parentId = args.parentId || null;
|
|
@@ -163,6 +173,7 @@ export async function createContentDatabaseRecord(
|
|
|
163
173
|
parentId,
|
|
164
174
|
title,
|
|
165
175
|
content: "",
|
|
176
|
+
description: args.description?.trim() ?? "",
|
|
166
177
|
icon: null,
|
|
167
178
|
position: (maxPos?.max ?? -1) + 1,
|
|
168
179
|
isFavorite: 0,
|
|
@@ -45,6 +45,12 @@ export default defineAction({
|
|
|
45
45
|
.describe("Pre-generated document ID (for optimistic UI)"),
|
|
46
46
|
title: z.string().describe("Document title"),
|
|
47
47
|
content: z.string().optional().describe("Markdown content"),
|
|
48
|
+
description: z
|
|
49
|
+
.string()
|
|
50
|
+
.optional()
|
|
51
|
+
.describe(
|
|
52
|
+
"Stable guidance describing why this page exists and what belongs in it",
|
|
53
|
+
),
|
|
48
54
|
parentId: z.string().nullish().describe("Parent document ID for nesting"),
|
|
49
55
|
icon: z.string().optional().describe("Emoji icon"),
|
|
50
56
|
}),
|
|
@@ -78,6 +84,7 @@ export default defineAction({
|
|
|
78
84
|
const title = args.title;
|
|
79
85
|
|
|
80
86
|
let content = args.content || "";
|
|
87
|
+
const description = args.description?.trim() ?? "";
|
|
81
88
|
// Strip leading H1 that duplicates the title
|
|
82
89
|
if (title && content) {
|
|
83
90
|
const h1Match = content.match(/^#\s+(.+?)(\r?\n|$)/);
|
|
@@ -154,6 +161,7 @@ export default defineAction({
|
|
|
154
161
|
parentId,
|
|
155
162
|
title,
|
|
156
163
|
content,
|
|
164
|
+
description,
|
|
157
165
|
icon,
|
|
158
166
|
position,
|
|
159
167
|
isFavorite: 0,
|
|
@@ -202,6 +210,7 @@ export default defineAction({
|
|
|
202
210
|
parentId: doc.parentId,
|
|
203
211
|
title: doc.title,
|
|
204
212
|
content: doc.content,
|
|
213
|
+
description: doc.description,
|
|
205
214
|
icon: doc.icon,
|
|
206
215
|
position: doc.position,
|
|
207
216
|
isFavorite: parseDocumentFavorite(doc.isFavorite),
|
|
@@ -22,10 +22,12 @@ export default defineAction({
|
|
|
22
22
|
schema: z.object({
|
|
23
23
|
hostDocumentId: z.string().describe("Host page document ID"),
|
|
24
24
|
title: z.string().optional().describe("Database title"),
|
|
25
|
+
description: z.string().optional().describe("Stable database guidance"),
|
|
25
26
|
}),
|
|
26
27
|
run: async ({
|
|
27
28
|
hostDocumentId,
|
|
28
29
|
title,
|
|
30
|
+
description,
|
|
29
31
|
}): Promise<CreateInlineDatabaseResponse> => {
|
|
30
32
|
const db = getDb();
|
|
31
33
|
const ownerBlockId = createInlineDatabaseBlockId();
|
|
@@ -37,6 +39,7 @@ export default defineAction({
|
|
|
37
39
|
{
|
|
38
40
|
parentId: hostDocumentId,
|
|
39
41
|
title: databaseTitleForPage(title),
|
|
42
|
+
description,
|
|
40
43
|
},
|
|
41
44
|
{ db: tx },
|
|
42
45
|
);
|
|
@@ -11,6 +11,7 @@ import type {
|
|
|
11
11
|
import {
|
|
12
12
|
CONTENT_DATABASE_MAX_READ_LIMIT,
|
|
13
13
|
getContentDatabaseResponse,
|
|
14
|
+
getDocumentContextPath,
|
|
14
15
|
} from "./_database-utils.js";
|
|
15
16
|
|
|
16
17
|
export default defineAction({
|
|
@@ -78,6 +79,17 @@ export default defineAction({
|
|
|
78
79
|
};
|
|
79
80
|
}
|
|
80
81
|
|
|
81
|
-
|
|
82
|
+
const response = await getContentDatabaseResponse(resolvedDatabaseId, {
|
|
83
|
+
limit,
|
|
84
|
+
offset,
|
|
85
|
+
});
|
|
86
|
+
const [document] = await db
|
|
87
|
+
.select()
|
|
88
|
+
.from(schema.documents)
|
|
89
|
+
.where(eq(schema.documents.id, database.documentId));
|
|
90
|
+
return {
|
|
91
|
+
...response,
|
|
92
|
+
contextPath: document ? await getDocumentContextPath(document) : [],
|
|
93
|
+
};
|
|
82
94
|
},
|
|
83
95
|
});
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
} from "../server/lib/documents.js";
|
|
10
10
|
import {
|
|
11
11
|
getDatabaseByDocumentId,
|
|
12
|
+
getDocumentContextPath,
|
|
12
13
|
getDatabaseItemByDocumentId,
|
|
13
14
|
isSoftDeletedDatabaseDocument,
|
|
14
15
|
serializeDatabaseMembership,
|
|
@@ -16,6 +17,7 @@ import {
|
|
|
16
17
|
import { serializeDocumentSource } from "./_document-source.js";
|
|
17
18
|
import {
|
|
18
19
|
getLocalFileDocument,
|
|
20
|
+
getLocalDocumentContextPath,
|
|
19
21
|
isLocalDocumentId,
|
|
20
22
|
isContentLocalFileMode,
|
|
21
23
|
} from "./_local-file-documents.js";
|
|
@@ -45,7 +47,11 @@ export default defineAction({
|
|
|
45
47
|
if (!args.id) throw new Error("--id is required");
|
|
46
48
|
|
|
47
49
|
if ((await isContentLocalFileMode()) && isLocalDocumentId(args.id)) {
|
|
48
|
-
|
|
50
|
+
const document = await getLocalFileDocument(args.id);
|
|
51
|
+
return {
|
|
52
|
+
...document,
|
|
53
|
+
contextPath: await getLocalDocumentContextPath(args.id),
|
|
54
|
+
};
|
|
49
55
|
}
|
|
50
56
|
|
|
51
57
|
const access = await resolveAccess("document", args.id);
|
|
@@ -76,6 +82,7 @@ export default defineAction({
|
|
|
76
82
|
parentId: doc.parentId,
|
|
77
83
|
title: doc.title,
|
|
78
84
|
content: doc.content,
|
|
85
|
+
description: doc.description,
|
|
79
86
|
icon: doc.icon,
|
|
80
87
|
position: doc.position,
|
|
81
88
|
isFavorite: parseDocumentFavorite(doc.isFavorite),
|
|
@@ -85,13 +92,16 @@ export default defineAction({
|
|
|
85
92
|
accessRole: access.role,
|
|
86
93
|
canEdit: canEditRole(access.role),
|
|
87
94
|
canManage: canManageRole(access.role),
|
|
88
|
-
database: database
|
|
95
|
+
database: database
|
|
96
|
+
? serializeDatabase(database, doc.description)
|
|
97
|
+
: undefined,
|
|
89
98
|
databaseMembership: databaseMembership
|
|
90
99
|
? serializeDatabaseMembership(databaseMembership)
|
|
91
100
|
: undefined,
|
|
92
101
|
createdAt: doc.createdAt,
|
|
93
102
|
updatedAt: doc.updatedAt,
|
|
94
103
|
properties: await listPropertiesForDocument(doc),
|
|
104
|
+
contextPath: await getDocumentContextPath(doc),
|
|
95
105
|
};
|
|
96
106
|
},
|
|
97
107
|
link: ({ result }) => {
|
|
@@ -282,6 +282,9 @@ export default defineAction({
|
|
|
282
282
|
}
|
|
283
283
|
const titleChanged = file.title !== existing.title;
|
|
284
284
|
const contentChanged = file.content !== existing.content;
|
|
285
|
+
const descriptionChanged =
|
|
286
|
+
file.description !== undefined &&
|
|
287
|
+
file.description !== existing.description;
|
|
285
288
|
const iconChanged =
|
|
286
289
|
file.icon !== undefined && file.icon !== existing.icon;
|
|
287
290
|
const favoriteChanged =
|
|
@@ -299,6 +302,7 @@ export default defineAction({
|
|
|
299
302
|
const anyChange =
|
|
300
303
|
titleChanged ||
|
|
301
304
|
contentChanged ||
|
|
305
|
+
descriptionChanged ||
|
|
302
306
|
iconChanged ||
|
|
303
307
|
favoriteChanged ||
|
|
304
308
|
discoverabilityChanged ||
|
|
@@ -322,6 +326,7 @@ export default defineAction({
|
|
|
322
326
|
const updates: Record<string, unknown> = { updatedAt: now };
|
|
323
327
|
if (titleChanged) updates.title = file.title;
|
|
324
328
|
if (contentChanged) updates.content = file.content;
|
|
329
|
+
if (descriptionChanged) updates.description = file.description;
|
|
325
330
|
if (iconChanged) updates.icon = file.icon ?? null;
|
|
326
331
|
if (favoriteChanged) updates.isFavorite = boolToInt(file.isFavorite);
|
|
327
332
|
if (discoverabilityChanged) {
|
|
@@ -347,6 +352,7 @@ export default defineAction({
|
|
|
347
352
|
orgId: currentOrgId,
|
|
348
353
|
parentId: null,
|
|
349
354
|
title: file.title,
|
|
355
|
+
description: file.description ?? "",
|
|
350
356
|
content: file.content,
|
|
351
357
|
icon: file.icon ?? null,
|
|
352
358
|
position: file.position ?? index,
|
|
@@ -70,6 +70,7 @@ export default defineAction({
|
|
|
70
70
|
id: schema.documents.id,
|
|
71
71
|
parentId: schema.documents.parentId,
|
|
72
72
|
title: schema.documents.title,
|
|
73
|
+
description: schema.documents.description,
|
|
73
74
|
contentSnippet: sql<string>`substr(${schema.documents.content}, 1, 400)`,
|
|
74
75
|
contentLength: sql<number>`length(${schema.documents.content})`,
|
|
75
76
|
icon: schema.documents.icon,
|
|
@@ -282,6 +283,7 @@ export default defineAction({
|
|
|
282
283
|
id: d.id,
|
|
283
284
|
parentId: d.parentId,
|
|
284
285
|
title: d.title,
|
|
286
|
+
description: d.description,
|
|
285
287
|
contentPreview: contentPreview(d.contentSnippet),
|
|
286
288
|
contentLength: Number(d.contentLength) || 0,
|
|
287
289
|
icon: d.icon,
|
|
@@ -299,6 +301,7 @@ export default defineAction({
|
|
|
299
301
|
id: database.id,
|
|
300
302
|
documentId: database.documentId,
|
|
301
303
|
title: database.title,
|
|
304
|
+
description: d.description,
|
|
302
305
|
viewConfig: parseDatabaseViewConfig(database.viewConfigJson),
|
|
303
306
|
createdAt: database.createdAt,
|
|
304
307
|
updatedAt: database.updatedAt,
|
|
@@ -73,6 +73,7 @@ export default defineAction({
|
|
|
73
73
|
return {
|
|
74
74
|
id: doc.id,
|
|
75
75
|
title: doc.title,
|
|
76
|
+
description: doc.description ?? "",
|
|
76
77
|
content: formatDocumentContent(doc.content ?? "", format),
|
|
77
78
|
format,
|
|
78
79
|
deepLink: buildDeepLink({
|
|
@@ -104,6 +105,7 @@ export default defineAction({
|
|
|
104
105
|
return {
|
|
105
106
|
id: doc.id,
|
|
106
107
|
title: doc.title,
|
|
108
|
+
description: (doc.description as string | null | undefined) ?? "",
|
|
107
109
|
content,
|
|
108
110
|
format,
|
|
109
111
|
deepLink: buildDeepLink({
|