@aopslab/domain-cli-docman 0.1.4

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/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@aopslab/domain-cli-docman",
3
+ "version": "0.1.4",
4
+ "private": false,
5
+ "type": "module",
6
+ "description": "Docman CLI (canonical invoke + generated sugar + optional hooks).",
7
+ "bin": {
8
+ "docman": "dist/main.js",
9
+ "docman-cli": "dist/main.js"
10
+ },
11
+ "files": [
12
+ "dist",
13
+ "resources",
14
+ "src",
15
+ "LICENSE",
16
+ "NOTICE"
17
+ ],
18
+ "dependencies": {
19
+ "@aopslab/xf-core": "0.1.69",
20
+ "@aopslab/xf-db-drizzle": "0.1.81",
21
+ "dotenv": "^17.3.1",
22
+ "@aopslab/domain-pg-bootstrap-docman": "0.1.0",
23
+ "@aopslab/domain-runtime-config-docman": "0.1.0",
24
+ "@aopslab/domain-host-plugin-docman": "0.1.4",
25
+ "@aopslab/domain-ops-docman": "0.1.4",
26
+ "@aopslab/domain-tooling-docman": "0.1.4"
27
+ },
28
+ "main": "dist/main.js",
29
+ "publishConfig": {
30
+ "access": "public",
31
+ "registry": "https://registry.npmjs.org"
32
+ },
33
+ "license": "Apache-2.0",
34
+ "repository": {
35
+ "type": "git",
36
+ "url": "git+https://github.com/eeemzs/docman.git",
37
+ "directory": "docman-cli"
38
+ },
39
+ "scripts": {
40
+ "prebuild": "pnpm -C .. --filter @aopslab/domain-runtime-config-docman run build && pnpm -C .. --filter @aopslab/domain-pg-bootstrap-docman run build",
41
+ "pretypecheck": "pnpm -C .. --filter @aopslab/domain-runtime-config-docman run build && pnpm -C .. --filter @aopslab/domain-pg-bootstrap-docman run build",
42
+ "build": "tsc -p tsconfig.app.json",
43
+ "postbuild": "pnpm run manifest:emit",
44
+ "build:all": "pnpm run build",
45
+ "start:node": "node dist/main.js",
46
+ "start:tsx": "tsx src/main.ts",
47
+ "typecheck": "tsc -p tsconfig.app.json --noEmit",
48
+ "manifest:print": "tsx scripts/manifest-cli.ts print",
49
+ "manifest:emit": "tsx scripts/manifest-cli.ts emit --out-dir dist/manifests",
50
+ "manifest:check": "tsx scripts/manifest-cli.ts check --out-dir dist/manifests"
51
+ }
52
+ }
@@ -0,0 +1,361 @@
1
+ PRAGMA foreign_keys = ON;
2
+
3
+ CREATE TABLE IF NOT EXISTS "docman_document_groups" (
4
+ "id" TEXT PRIMARY KEY NOT NULL,
5
+ "tenantId" TEXT NOT NULL,
6
+ "scopeId" TEXT NOT NULL,
7
+ "groupUid" TEXT NOT NULL,
8
+ "parentGroupId" TEXT,
9
+ "parentGroupUid" TEXT,
10
+ "title" TEXT NOT NULL,
11
+ "description" TEXT,
12
+ "meta" TEXT,
13
+ "createdBy" TEXT,
14
+ "updatedBy" TEXT,
15
+ "createdAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER)),
16
+ "updatedAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER))
17
+ );
18
+ CREATE UNIQUE INDEX IF NOT EXISTS "document_group_uid_unique" ON "docman_document_groups" ("tenantId", "scopeId", "groupUid");
19
+ CREATE INDEX IF NOT EXISTS "document_group_idx_tenant" ON "docman_document_groups" ("tenantId");
20
+ CREATE INDEX IF NOT EXISTS "document_group_idx_scope" ON "docman_document_groups" ("tenantId", "scopeId");
21
+ CREATE INDEX IF NOT EXISTS "document_group_idx_parent" ON "docman_document_groups" ("tenantId", "parentGroupId");
22
+
23
+ CREATE TABLE IF NOT EXISTS "docman_documents" (
24
+ "id" TEXT PRIMARY KEY NOT NULL,
25
+ "tenantId" TEXT NOT NULL,
26
+ "scopeId" TEXT NOT NULL,
27
+ "documentUid" TEXT NOT NULL,
28
+ "groupId" TEXT,
29
+ "groupUid" TEXT,
30
+ "slug" TEXT,
31
+ "title" TEXT NOT NULL,
32
+ "titleMl" TEXT,
33
+ "summary" TEXT,
34
+ "summaryMl" TEXT,
35
+ "description" TEXT,
36
+ "descriptionMl" TEXT,
37
+ "status" TEXT NOT NULL,
38
+ "visibility" TEXT NOT NULL,
39
+ "tags" TEXT,
40
+ "pageSize" TEXT,
41
+ "meta" TEXT,
42
+ "createdBy" TEXT,
43
+ "updatedBy" TEXT,
44
+ "createdAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER)),
45
+ "updatedAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER))
46
+ );
47
+ CREATE UNIQUE INDEX IF NOT EXISTS "document_uid_unique" ON "docman_documents" ("tenantId", "scopeId", "documentUid");
48
+ CREATE INDEX IF NOT EXISTS "document_idx_tenant" ON "docman_documents" ("tenantId");
49
+ CREATE INDEX IF NOT EXISTS "document_idx_scope" ON "docman_documents" ("tenantId", "scopeId");
50
+ CREATE INDEX IF NOT EXISTS "document_idx_status" ON "docman_documents" ("tenantId", "status");
51
+ CREATE INDEX IF NOT EXISTS "document_idx_scope_slug" ON "docman_documents" ("tenantId", "scopeId", "slug");
52
+ CREATE INDEX IF NOT EXISTS "document_idx_scope_group_id" ON "docman_documents" ("tenantId", "scopeId", "groupId");
53
+ CREATE INDEX IF NOT EXISTS "document_idx_scope_group_uid" ON "docman_documents" ("tenantId", "scopeId", "groupUid");
54
+
55
+ CREATE TABLE IF NOT EXISTS "docman_document_versions" (
56
+ "id" TEXT PRIMARY KEY NOT NULL,
57
+ "tenantId" TEXT NOT NULL,
58
+ "documentId" TEXT NOT NULL,
59
+ "version" INTEGER NOT NULL,
60
+ "label" TEXT,
61
+ "status" TEXT NOT NULL,
62
+ "title" TEXT,
63
+ "summary" TEXT,
64
+ "releaseNotes" TEXT,
65
+ "releaseNotesMl" TEXT,
66
+ "isCurrent" INTEGER NOT NULL DEFAULT 0,
67
+ "basedOnVersionId" TEXT,
68
+ "publishedAt" INTEGER,
69
+ "createdBy" TEXT,
70
+ "updatedBy" TEXT,
71
+ "createdAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER)),
72
+ "updatedAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER))
73
+ );
74
+ CREATE UNIQUE INDEX IF NOT EXISTS "document_version_unique" ON "docman_document_versions" ("tenantId", "documentId", "version");
75
+ CREATE INDEX IF NOT EXISTS "document_version_idx_doc" ON "docman_document_versions" ("tenantId", "documentId");
76
+ CREATE INDEX IF NOT EXISTS "document_version_idx_status" ON "docman_document_versions" ("tenantId", "status");
77
+ CREATE INDEX IF NOT EXISTS "document_version_idx_current" ON "docman_document_versions" ("tenantId", "documentId", "isCurrent");
78
+
79
+ CREATE TABLE IF NOT EXISTS "docman_sections" (
80
+ "id" TEXT PRIMARY KEY NOT NULL,
81
+ "tenantId" TEXT NOT NULL,
82
+ "scopeId" TEXT NOT NULL,
83
+ "sectionUid" TEXT NOT NULL,
84
+ "title" TEXT NOT NULL,
85
+ "titleMl" TEXT,
86
+ "kind" TEXT,
87
+ "slug" TEXT,
88
+ "createdBy" TEXT,
89
+ "updatedBy" TEXT,
90
+ "createdAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER)),
91
+ "updatedAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER))
92
+ );
93
+ CREATE UNIQUE INDEX IF NOT EXISTS "section_uid_unique" ON "docman_sections" ("tenantId", "scopeId", "sectionUid");
94
+ CREATE INDEX IF NOT EXISTS "section_idx_tenant" ON "docman_sections" ("tenantId");
95
+ CREATE INDEX IF NOT EXISTS "section_idx_scope" ON "docman_sections" ("tenantId", "scopeId");
96
+
97
+ CREATE TABLE IF NOT EXISTS "docman_pages" (
98
+ "id" TEXT PRIMARY KEY NOT NULL,
99
+ "tenantId" TEXT NOT NULL,
100
+ "scopeId" TEXT NOT NULL,
101
+ "pageUid" TEXT NOT NULL,
102
+ "title" TEXT NOT NULL,
103
+ "titleMl" TEXT,
104
+ "kind" TEXT,
105
+ "meta" TEXT,
106
+ "createdBy" TEXT,
107
+ "updatedBy" TEXT,
108
+ "createdAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER)),
109
+ "updatedAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER))
110
+ );
111
+ CREATE UNIQUE INDEX IF NOT EXISTS "page_uid_unique" ON "docman_pages" ("tenantId", "scopeId", "pageUid");
112
+ CREATE INDEX IF NOT EXISTS "page_idx_tenant" ON "docman_pages" ("tenantId");
113
+ CREATE INDEX IF NOT EXISTS "page_idx_scope" ON "docman_pages" ("tenantId", "scopeId");
114
+
115
+ CREATE TABLE IF NOT EXISTS "docman_page_versions" (
116
+ "id" TEXT PRIMARY KEY NOT NULL,
117
+ "tenantId" TEXT NOT NULL,
118
+ "pageId" TEXT NOT NULL,
119
+ "version" INTEGER NOT NULL,
120
+ "title" TEXT,
121
+ "format" TEXT NOT NULL,
122
+ "content" TEXT,
123
+ "contentMl" TEXT,
124
+ "contentData" TEXT,
125
+ "directives" TEXT,
126
+ "status" TEXT NOT NULL,
127
+ "createdBy" TEXT,
128
+ "updatedBy" TEXT,
129
+ "createdAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER)),
130
+ "updatedAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER))
131
+ );
132
+ CREATE UNIQUE INDEX IF NOT EXISTS "page_version_unique" ON "docman_page_versions" ("tenantId", "pageId", "version");
133
+ CREATE INDEX IF NOT EXISTS "page_version_idx_page" ON "docman_page_versions" ("tenantId", "pageId");
134
+ CREATE INDEX IF NOT EXISTS "page_version_idx_status" ON "docman_page_versions" ("tenantId", "status");
135
+
136
+ CREATE TABLE IF NOT EXISTS "docman_document_section_links" (
137
+ "id" TEXT PRIMARY KEY NOT NULL,
138
+ "tenantId" TEXT NOT NULL,
139
+ "documentVersionId" TEXT NOT NULL,
140
+ "kind" TEXT NOT NULL,
141
+ "sectionId" TEXT,
142
+ "pageVersionId" TEXT,
143
+ "parentLinkId" TEXT,
144
+ "position" INTEGER NOT NULL,
145
+ "depth" INTEGER,
146
+ "titleOverride" TEXT,
147
+ "titleVisible" INTEGER NOT NULL DEFAULT 1,
148
+ "numbering" TEXT,
149
+ "pageBreakBefore" INTEGER NOT NULL DEFAULT 0,
150
+ "pageBreakAfter" INTEGER NOT NULL DEFAULT 0,
151
+ "directives" TEXT,
152
+ "createdBy" TEXT,
153
+ "updatedBy" TEXT,
154
+ "createdAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER)),
155
+ "updatedAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER))
156
+ );
157
+ CREATE UNIQUE INDEX IF NOT EXISTS "doc_section_pos_unique" ON "docman_document_section_links" ("tenantId", "documentVersionId", "parentLinkId", "position");
158
+ CREATE INDEX IF NOT EXISTS "doc_section_idx_doc_version" ON "docman_document_section_links" ("tenantId", "documentVersionId");
159
+ CREATE INDEX IF NOT EXISTS "doc_section_idx_section" ON "docman_document_section_links" ("tenantId", "sectionId");
160
+ CREATE INDEX IF NOT EXISTS "doc_section_idx_page_version" ON "docman_document_section_links" ("tenantId", "pageVersionId");
161
+ CREATE INDEX IF NOT EXISTS "doc_section_idx_parent" ON "docman_document_section_links" ("tenantId", "parentLinkId");
162
+
163
+ CREATE TABLE IF NOT EXISTS "docman_section_page_links" (
164
+ "id" TEXT PRIMARY KEY NOT NULL,
165
+ "tenantId" TEXT NOT NULL,
166
+ "sectionId" TEXT NOT NULL,
167
+ "pageVersionId" TEXT NOT NULL,
168
+ "position" INTEGER NOT NULL,
169
+ "numbering" TEXT,
170
+ "titleOverride" TEXT,
171
+ "titleVisible" INTEGER NOT NULL DEFAULT 1,
172
+ "pageBreakBefore" INTEGER NOT NULL DEFAULT 0,
173
+ "pageBreakAfter" INTEGER NOT NULL DEFAULT 0,
174
+ "createdBy" TEXT,
175
+ "updatedBy" TEXT,
176
+ "createdAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER)),
177
+ "updatedAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER))
178
+ );
179
+ CREATE UNIQUE INDEX IF NOT EXISTS "section_page_pos_unique" ON "docman_section_page_links" ("tenantId", "sectionId", "position");
180
+ CREATE INDEX IF NOT EXISTS "section_page_idx_section" ON "docman_section_page_links" ("tenantId", "sectionId");
181
+ CREATE INDEX IF NOT EXISTS "section_page_idx_page_version" ON "docman_section_page_links" ("tenantId", "pageVersionId");
182
+
183
+ CREATE TABLE IF NOT EXISTS "docman_snippets" (
184
+ "id" TEXT PRIMARY KEY NOT NULL,
185
+ "tenantId" TEXT NOT NULL,
186
+ "scopeId" TEXT NOT NULL,
187
+ "snippetUid" TEXT NOT NULL,
188
+ "title" TEXT,
189
+ "language" TEXT NOT NULL,
190
+ "code" TEXT NOT NULL,
191
+ "description" TEXT,
192
+ "meta" TEXT,
193
+ "createdBy" TEXT,
194
+ "updatedBy" TEXT,
195
+ "createdAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER)),
196
+ "updatedAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER))
197
+ );
198
+ CREATE UNIQUE INDEX IF NOT EXISTS "snippet_uid_unique" ON "docman_snippets" ("tenantId", "scopeId", "snippetUid");
199
+ CREATE INDEX IF NOT EXISTS "snippet_idx_tenant" ON "docman_snippets" ("tenantId");
200
+ CREATE INDEX IF NOT EXISTS "snippet_idx_scope" ON "docman_snippets" ("tenantId", "scopeId");
201
+ CREATE INDEX IF NOT EXISTS "snippet_idx_scope_language" ON "docman_snippets" ("tenantId", "scopeId", "language");
202
+
203
+ CREATE TABLE IF NOT EXISTS "docman_page_snippet_links" (
204
+ "id" TEXT PRIMARY KEY NOT NULL,
205
+ "tenantId" TEXT NOT NULL,
206
+ "pageVersionId" TEXT NOT NULL,
207
+ "snippetId" TEXT NOT NULL,
208
+ "position" INTEGER NOT NULL,
209
+ "caption" TEXT,
210
+ "showLineNumbers" INTEGER,
211
+ "createdBy" TEXT,
212
+ "updatedBy" TEXT,
213
+ "createdAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER)),
214
+ "updatedAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER))
215
+ );
216
+ CREATE UNIQUE INDEX IF NOT EXISTS "page_snippet_pos_unique" ON "docman_page_snippet_links" ("tenantId", "pageVersionId", "position");
217
+ CREATE INDEX IF NOT EXISTS "page_snippet_idx_page_version" ON "docman_page_snippet_links" ("tenantId", "pageVersionId");
218
+ CREATE INDEX IF NOT EXISTS "page_snippet_idx_snippet" ON "docman_page_snippet_links" ("tenantId", "snippetId");
219
+
220
+ CREATE TABLE IF NOT EXISTS "docman_assets" (
221
+ "id" TEXT PRIMARY KEY NOT NULL,
222
+ "tenantId" TEXT NOT NULL,
223
+ "scopeId" TEXT NOT NULL,
224
+ "assetUid" TEXT NOT NULL,
225
+ "kind" TEXT NOT NULL,
226
+ "title" TEXT,
227
+ "slug" TEXT,
228
+ "altText" TEXT,
229
+ "currentVersionId" TEXT,
230
+ "meta" TEXT,
231
+ "createdBy" TEXT,
232
+ "updatedBy" TEXT,
233
+ "createdAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER)),
234
+ "updatedAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER))
235
+ );
236
+ CREATE UNIQUE INDEX IF NOT EXISTS "asset_uid_unique" ON "docman_assets" ("tenantId", "scopeId", "assetUid");
237
+ CREATE INDEX IF NOT EXISTS "asset_idx_tenant" ON "docman_assets" ("tenantId");
238
+ CREATE INDEX IF NOT EXISTS "asset_idx_scope" ON "docman_assets" ("tenantId", "scopeId");
239
+ CREATE INDEX IF NOT EXISTS "asset_idx_scope_kind" ON "docman_assets" ("tenantId", "scopeId", "kind");
240
+ CREATE INDEX IF NOT EXISTS "asset_idx_scope_current_version" ON "docman_assets" ("tenantId", "scopeId", "currentVersionId");
241
+
242
+ CREATE TABLE IF NOT EXISTS "docman_asset_versions" (
243
+ "id" TEXT PRIMARY KEY NOT NULL,
244
+ "tenantId" TEXT NOT NULL,
245
+ "assetId" TEXT NOT NULL,
246
+ "version" INTEGER NOT NULL,
247
+ "label" TEXT,
248
+ "status" TEXT NOT NULL,
249
+ "storageKey" TEXT,
250
+ "sourcePath" TEXT,
251
+ "sourceUrl" TEXT,
252
+ "filename" TEXT,
253
+ "mime" TEXT NOT NULL,
254
+ "contentHash" TEXT NOT NULL,
255
+ "byteSize" INTEGER,
256
+ "width" INTEGER,
257
+ "height" INTEGER,
258
+ "variants" TEXT,
259
+ "meta" TEXT,
260
+ "createdBy" TEXT,
261
+ "updatedBy" TEXT,
262
+ "createdAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER)),
263
+ "updatedAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER))
264
+ );
265
+ CREATE UNIQUE INDEX IF NOT EXISTS "asset_version_unique" ON "docman_asset_versions" ("tenantId", "assetId", "version");
266
+ CREATE INDEX IF NOT EXISTS "asset_version_idx_asset" ON "docman_asset_versions" ("tenantId", "assetId");
267
+ CREATE INDEX IF NOT EXISTS "asset_version_idx_status" ON "docman_asset_versions" ("tenantId", "status");
268
+ CREATE INDEX IF NOT EXISTS "asset_version_idx_hash" ON "docman_asset_versions" ("tenantId", "contentHash");
269
+
270
+ CREATE TABLE IF NOT EXISTS "docman_document_index_entries" (
271
+ "id" TEXT PRIMARY KEY NOT NULL,
272
+ "tenantId" TEXT NOT NULL,
273
+ "documentVersionId" TEXT NOT NULL,
274
+ "documentId" TEXT NOT NULL,
275
+ "locale" TEXT NOT NULL DEFAULT '',
276
+ "fallbackLocale" TEXT NOT NULL DEFAULT '',
277
+ "itemKind" TEXT NOT NULL,
278
+ "sortOrder" INTEGER NOT NULL,
279
+ "buildFingerprint" TEXT NOT NULL,
280
+ "linkId" TEXT,
281
+ "parentLinkId" TEXT,
282
+ "anchor" TEXT NOT NULL,
283
+ "parentAnchor" TEXT,
284
+ "number" TEXT,
285
+ "depth" INTEGER NOT NULL,
286
+ "position" INTEGER NOT NULL,
287
+ "title" TEXT NOT NULL,
288
+ "breadcrumb" TEXT NOT NULL,
289
+ "titleVisible" INTEGER NOT NULL DEFAULT 1,
290
+ "pageBreakBefore" INTEGER NOT NULL DEFAULT 0,
291
+ "pageBreakAfter" INTEGER NOT NULL DEFAULT 0,
292
+ "sectionId" TEXT,
293
+ "sectionUid" TEXT,
294
+ "sectionSlug" TEXT,
295
+ "pageId" TEXT,
296
+ "pageUid" TEXT,
297
+ "pageVersionId" TEXT,
298
+ "format" TEXT,
299
+ "pageNumberStart" INTEGER,
300
+ "pageNumberEnd" INTEGER,
301
+ "bodyText" TEXT,
302
+ "summaryText" TEXT,
303
+ "sourceCharCount" INTEGER NOT NULL DEFAULT 0,
304
+ "sourceWordCount" INTEGER NOT NULL DEFAULT 0,
305
+ "summaryCharCount" INTEGER NOT NULL DEFAULT 0,
306
+ "summaryWordCount" INTEGER NOT NULL DEFAULT 0,
307
+ "embeddingProvider" TEXT,
308
+ "embeddingModel" TEXT,
309
+ "embeddingHash" TEXT,
310
+ "embeddingDimensions" INTEGER,
311
+ "embeddingVector" TEXT,
312
+ "searchText" TEXT NOT NULL,
313
+ "createdBy" TEXT,
314
+ "updatedBy" TEXT,
315
+ "createdAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER)),
316
+ "updatedAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER))
317
+ );
318
+ CREATE UNIQUE INDEX IF NOT EXISTS "doc_index_entry_sort_unique" ON "docman_document_index_entries" ("tenantId", "documentVersionId", "locale", "fallbackLocale", "sortOrder");
319
+ CREATE UNIQUE INDEX IF NOT EXISTS "doc_index_entry_anchor_unique" ON "docman_document_index_entries" ("tenantId", "documentVersionId", "locale", "fallbackLocale", "anchor");
320
+ CREATE INDEX IF NOT EXISTS "doc_index_entry_idx_doc_version" ON "docman_document_index_entries" ("tenantId", "documentVersionId", "locale", "fallbackLocale");
321
+ CREATE INDEX IF NOT EXISTS "doc_index_entry_idx_link" ON "docman_document_index_entries" ("tenantId", "linkId");
322
+ CREATE INDEX IF NOT EXISTS "doc_index_entry_idx_page_version" ON "docman_document_index_entries" ("tenantId", "pageVersionId");
323
+ CREATE INDEX IF NOT EXISTS "doc_index_entry_idx_section" ON "docman_document_index_entries" ("tenantId", "sectionId");
324
+
325
+ CREATE TABLE IF NOT EXISTS "docman_embeds" (
326
+ "id" TEXT PRIMARY KEY NOT NULL,
327
+ "tenantId" TEXT NOT NULL,
328
+ "scopeId" TEXT NOT NULL,
329
+ "embedUid" TEXT NOT NULL,
330
+ "type" TEXT NOT NULL,
331
+ "title" TEXT,
332
+ "content" TEXT,
333
+ "url" TEXT,
334
+ "path" TEXT,
335
+ "mime" TEXT,
336
+ "meta" TEXT,
337
+ "createdBy" TEXT,
338
+ "updatedBy" TEXT,
339
+ "createdAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER)),
340
+ "updatedAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER))
341
+ );
342
+ CREATE UNIQUE INDEX IF NOT EXISTS "embed_uid_unique" ON "docman_embeds" ("tenantId", "scopeId", "embedUid");
343
+ CREATE INDEX IF NOT EXISTS "embed_idx_tenant" ON "docman_embeds" ("tenantId");
344
+ CREATE INDEX IF NOT EXISTS "embed_idx_scope" ON "docman_embeds" ("tenantId", "scopeId");
345
+ CREATE INDEX IF NOT EXISTS "embed_idx_scope_type" ON "docman_embeds" ("tenantId", "scopeId", "type");
346
+
347
+ CREATE TABLE IF NOT EXISTS "docman_page_embed_links" (
348
+ "id" TEXT PRIMARY KEY NOT NULL,
349
+ "tenantId" TEXT NOT NULL,
350
+ "pageVersionId" TEXT NOT NULL,
351
+ "embedId" TEXT NOT NULL,
352
+ "position" INTEGER NOT NULL,
353
+ "caption" TEXT,
354
+ "createdBy" TEXT,
355
+ "updatedBy" TEXT,
356
+ "createdAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER)),
357
+ "updatedAt" INTEGER NOT NULL DEFAULT (CAST((julianday('now') - 2440587.5) * 86400000 AS INTEGER))
358
+ );
359
+ CREATE UNIQUE INDEX IF NOT EXISTS "page_embed_pos_unique" ON "docman_page_embed_links" ("tenantId", "pageVersionId", "position");
360
+ CREATE INDEX IF NOT EXISTS "page_embed_idx_page_version" ON "docman_page_embed_links" ("tenantId", "pageVersionId");
361
+ CREATE INDEX IF NOT EXISTS "page_embed_idx_embed" ON "docman_page_embed_links" ("tenantId", "embedId");
@@ -0,0 +1,33 @@
1
+ export type OptionValue = boolean | string | string[]
2
+
3
+ export type ParsedArgv = {
4
+ positionals: string[]
5
+ options: Record<string, OptionValue>
6
+ }
7
+
8
+ export type RuntimeContext = {
9
+ scopeId: string
10
+ workspaceId: string
11
+ tenantId: string
12
+ }
13
+
14
+ export type DocmanExecutionMode = 'host' | 'tooling'
15
+
16
+ export type DocmanOperationSpec = {
17
+ operationId: string
18
+ toolId?: string
19
+ summary?: string
20
+ sideEffect?: 'none' | 'db' | 'mixed'
21
+ tags?: string[]
22
+ examples?: string[]
23
+ docs?: {
24
+ notes?: string[]
25
+ antiPatterns?: string[]
26
+ preconditions?: string[]
27
+ postconditions?: string[]
28
+ }
29
+ args: Array<{
30
+ name: string
31
+ optional?: boolean
32
+ }>
33
+ }
@@ -0,0 +1,87 @@
1
+ import type { DocmanCliStoredConfigPatch, LoadedDocmanCliStoredConfig } from './config-host.js'
2
+ import type { ParsedArgv } from './cli-types.js'
3
+
4
+ type DocmanCliCommandSurfaceDeps = {
5
+ buildConfigSetOutput: (stored: LoadedDocmanCliStoredConfig) => Record<string, unknown>
6
+ buildConfigShowOutput: (processEnv: NodeJS.ProcessEnv) => Record<string, unknown>
7
+ getStringOption: (parsed: ParsedArgv, key: string) => string | undefined
8
+ parseJsonInput: (raw: unknown, label: string) => unknown
9
+ printJson: (value: unknown) => void
10
+ runOperationById: (operationId: string, input?: unknown) => Promise<unknown>
11
+ writeStoredConfig: (
12
+ patch: DocmanCliStoredConfigPatch,
13
+ processEnv?: NodeJS.ProcessEnv,
14
+ ) => LoadedDocmanCliStoredConfig
15
+ }
16
+
17
+ export function createDocmanCliCommandSurface(deps: DocmanCliCommandSurfaceDeps) {
18
+ async function handleConfig(subcommand: string | undefined, parsed: ParsedArgv): Promise<void> {
19
+ if (subcommand === 'show') {
20
+ deps.printJson(deps.buildConfigShowOutput(process.env))
21
+ return
22
+ }
23
+
24
+ if (subcommand === 'set') {
25
+ const patch: DocmanCliStoredConfigPatch = {}
26
+ const repoUrl = deps.getStringOption(parsed, 'repo-url')
27
+ const scopeId = deps.getStringOption(parsed, 'scope-id') ?? deps.getStringOption(parsed, 'workspace-id')
28
+ const runtimeModeRaw = deps.getStringOption(parsed, 'runtime-mode')
29
+ const tenantId = deps.getStringOption(parsed, 'tenant-id')
30
+ const logLevel = deps.getStringOption(parsed, 'log-level')
31
+ const hostConfigPath = deps.getStringOption(parsed, 'host-config')
32
+ const executionModeRaw = deps.getStringOption(parsed, 'execution-mode')
33
+
34
+ if (repoUrl) patch.repoUrl = repoUrl
35
+ if (scopeId) patch.scopeId = scopeId
36
+ if (runtimeModeRaw) {
37
+ const runtimeMode = runtimeModeRaw.trim().toLowerCase()
38
+ if (runtimeMode !== 'single-user' && runtimeMode !== 'multi-user') {
39
+ throw new Error(`invalid_runtime_mode:${runtimeModeRaw}`)
40
+ }
41
+ patch.runtimeMode = runtimeMode
42
+ }
43
+ if (tenantId) patch.tenantId = tenantId
44
+ if (logLevel) patch.logLevel = logLevel
45
+ if (hostConfigPath) patch.hostConfigPath = hostConfigPath
46
+ if (executionModeRaw) {
47
+ const executionMode = executionModeRaw.trim().toLowerCase()
48
+ if (executionMode !== 'host' && executionMode !== 'tooling') {
49
+ throw new Error(`invalid_execution_mode:${executionModeRaw}`)
50
+ }
51
+ patch.executionMode = executionMode
52
+ }
53
+
54
+ if (Object.keys(patch).length === 0) {
55
+ throw new Error('missing_config_patch:provide_at_least_one_option')
56
+ }
57
+
58
+ const stored = deps.writeStoredConfig(patch, process.env)
59
+ deps.printJson(deps.buildConfigSetOutput(stored))
60
+ return
61
+ }
62
+
63
+ throw new Error(`unknown_config_subcommand:${subcommand ?? '<missing>'}`)
64
+ }
65
+
66
+ async function tryExecuteOperationViaHook(operationId: string, parsed: ParsedArgv): Promise<boolean> {
67
+ if (operationId === 'docman.document.get') {
68
+ const id = deps.getStringOption(parsed, 'id')
69
+ const documentId = deps.getStringOption(parsed, 'document-id')
70
+ if (id || !documentId) return false
71
+
72
+ const input: Record<string, unknown> = { id: documentId }
73
+ const options = deps.parseJsonInput(deps.getStringOption(parsed, 'options'), 'options')
74
+ if (options !== undefined) input.options = options
75
+ const output = await deps.runOperationById(operationId, input)
76
+ deps.printJson(output)
77
+ return true
78
+ }
79
+
80
+ return false
81
+ }
82
+
83
+ return {
84
+ handleConfig,
85
+ tryExecuteOperationViaHook,
86
+ }
87
+ }
@@ -0,0 +1,24 @@
1
+ export {
2
+ DEFAULT_DOCMAN_SCOPE_ID,
3
+ applyDocmanRuntimeEnv,
4
+ getDefaultDocmanSqlitePath,
5
+ getDefaultDocmanSqliteRepoUrl,
6
+ getDocmanConfigDir as getDocmanCliConfigDir,
7
+ getDocmanConfigPath as getDocmanCliConfigPath,
8
+ inferDocmanRepoDialect,
9
+ isDocmanSqliteRepoUrl,
10
+ readDocmanStoredConfig as readDocmanCliStoredConfig,
11
+ resolveDocmanRuntimeConfig,
12
+ writeDocmanStoredConfig as writeDocmanCliStoredConfig,
13
+ } from '@aopslab/domain-runtime-config-docman'
14
+
15
+ export type {
16
+ DocmanCliExecutionMode,
17
+ DocmanConfigSource,
18
+ DocmanRepoDialect,
19
+ DocmanRuntimeMode,
20
+ DocmanStoredConfig as DocmanCliStoredConfig,
21
+ DocmanStoredConfigPatch as DocmanCliStoredConfigPatch,
22
+ LoadedDocmanStoredConfig as LoadedDocmanCliStoredConfig,
23
+ ResolvedDocmanRuntimeConfig,
24
+ } from '@aopslab/domain-runtime-config-docman'
@@ -0,0 +1,111 @@
1
+ import { config as dotenvConfig } from 'dotenv'
2
+ import { existsSync } from 'node:fs'
3
+ import { resolve } from 'node:path'
4
+ import { fileURLToPath } from 'node:url'
5
+ import { readDocmanCliStoredConfig } from './config-host.js'
6
+
7
+ const cliRoot = fileURLToPath(new URL('../', import.meta.url))
8
+ const envPaths = [
9
+ resolve(cliRoot, '..', '.env'),
10
+ resolve(cliRoot, '..', '..', '..', 'apps', 'aops', '.env'),
11
+ ]
12
+
13
+ type ParsedBootstrapArgv = {
14
+ positionals: string[]
15
+ options: Record<string, string | boolean>
16
+ }
17
+
18
+ function normalizeNonEmptyString(value: unknown): string | undefined {
19
+ if (typeof value !== 'string') return undefined
20
+ const normalized = value.trim()
21
+ return normalized.length > 0 ? normalized : undefined
22
+ }
23
+
24
+ function normalizeRepoUrlValue(value: unknown): string | undefined {
25
+ const normalized = normalizeNonEmptyString(value)
26
+ if (!normalized) return undefined
27
+ return normalized.replace(/(?:\\r|\r)+$/g, '')
28
+ }
29
+
30
+ function inferRepoDialectFromUrl(repoUrl: string): 'pg' | 'sqlite' {
31
+ const normalized = repoUrl.trim().toLowerCase()
32
+ if (!normalized) return 'pg'
33
+ if (normalized === ':memory:') return 'sqlite'
34
+ if (normalized.startsWith('sqlite:') || normalized.startsWith('file:')) return 'sqlite'
35
+ if (normalized.endsWith('.db') || normalized.endsWith('.sqlite') || normalized.endsWith('.sqlite3')) return 'sqlite'
36
+ return 'pg'
37
+ }
38
+
39
+ function normalizeOptionKey(raw: string): string {
40
+ return raw.trim().replace(/^--+/, '').toLowerCase()
41
+ }
42
+
43
+ function parseBootstrapArgv(argv: string[]): ParsedBootstrapArgv {
44
+ const positionals: string[] = []
45
+ const options: Record<string, string | boolean> = {}
46
+
47
+ for (let index = 0; index < argv.length; index += 1) {
48
+ const token = argv[index]
49
+ if (token === '--') continue
50
+
51
+ if (!token.startsWith('--')) {
52
+ positionals.push(token)
53
+ continue
54
+ }
55
+
56
+ const eqAt = token.indexOf('=')
57
+ if (eqAt > -1) {
58
+ options[normalizeOptionKey(token.slice(0, eqAt))] = token.slice(eqAt + 1)
59
+ continue
60
+ }
61
+
62
+ const key = normalizeOptionKey(token)
63
+ const next = argv[index + 1]
64
+ if (!next || next.startsWith('--')) {
65
+ options[key] = true
66
+ continue
67
+ }
68
+
69
+ options[key] = next
70
+ index += 1
71
+ }
72
+
73
+ return { positionals, options }
74
+ }
75
+
76
+ function getStringOption(parsed: ParsedBootstrapArgv, key: string): string | undefined {
77
+ const value = parsed.options[key]
78
+ return normalizeNonEmptyString(value)
79
+ }
80
+
81
+ for (const envPath of envPaths) {
82
+ if (existsSync(envPath)) {
83
+ dotenvConfig({ path: envPath, override: false, quiet: true })
84
+ }
85
+ }
86
+
87
+ const parsed = parseBootstrapArgv(process.argv.slice(2))
88
+ const command = parsed.positionals[0]?.toLowerCase()
89
+ const isConfigCommand = command === 'config'
90
+ const storedConfig = readDocmanCliStoredConfig(process.env).config
91
+
92
+ if (
93
+ !isConfigCommand &&
94
+ !normalizeRepoUrlValue(process.env.DOCMAN_REPO_URL) &&
95
+ !normalizeRepoUrlValue(process.env.DOCMAN_SQLITE_URL) &&
96
+ !normalizeRepoUrlValue(process.env.DOCMAN_PG_URL) &&
97
+ !getStringOption(parsed, 'repo-url')
98
+ ) {
99
+ const storedRepoUrl = normalizeRepoUrlValue(storedConfig.repoUrl)
100
+ if (storedRepoUrl) {
101
+ process.env.DOCMAN_REPO_URL = storedRepoUrl
102
+ if (inferRepoDialectFromUrl(storedRepoUrl) === 'sqlite') {
103
+ process.env.DOCMAN_SQLITE_URL = storedRepoUrl
104
+ delete process.env.DOCMAN_PG_URL
105
+ } else {
106
+ process.env.DOCMAN_PG_URL = storedRepoUrl
107
+ delete process.env.DOCMAN_SQLITE_URL
108
+ }
109
+ process.env.DOCMAN_CLI_BOOTSTRAPPED_REPO_URL_SOURCE = 'stored-config'
110
+ }
111
+ }