@google-cloud/kcmd 0.0.0-stage → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +203 -0
- package/README.md +266 -2
- package/build/ts/kcmd/cli.js +19578 -0
- package/build/ts/kcmd/gcp/alloydb.d.ts +12 -0
- package/build/ts/kcmd/gcp/alloydb.js +70 -0
- package/build/ts/kcmd/gcp/api.d.ts +29 -0
- package/build/ts/kcmd/gcp/api.js +162 -0
- package/build/ts/kcmd/gcp/biglake.d.ts +16 -0
- package/build/ts/kcmd/gcp/biglake.js +50 -0
- package/build/ts/kcmd/gcp/bigquery.d.ts +57 -0
- package/build/ts/kcmd/gcp/bigquery.js +134 -0
- package/build/ts/kcmd/gcp/context.d.ts +10 -0
- package/build/ts/kcmd/gcp/context.js +74 -0
- package/build/ts/kcmd/gcp/crm.d.ts +13 -0
- package/build/ts/kcmd/gcp/crm.js +91 -0
- package/build/ts/kcmd/gcp/dataplex.d.ts +147 -0
- package/build/ts/kcmd/gcp/dataplex.js +406 -0
- package/build/ts/kcmd/gcp/index.d.ts +3 -0
- package/build/ts/kcmd/gcp/index.js +21 -0
- package/build/ts/kcmd/gcp/spanner.d.ts +63 -0
- package/build/ts/kcmd/gcp/spanner.js +123 -0
- package/build/ts/kcmd/index.d.ts +7 -0
- package/build/ts/kcmd/index.js +46 -0
- package/build/ts/kcmd/layout.d.ts +16 -0
- package/build/ts/kcmd/layout.js +31 -0
- package/build/ts/kcmd/layouts/documents.d.ts +24 -0
- package/build/ts/kcmd/layouts/documents.js +264 -0
- package/build/ts/kcmd/layouts/okf.d.ts +31 -0
- package/build/ts/kcmd/layouts/okf.js +344 -0
- package/build/ts/kcmd/layouts/semantic-model.d.ts +61 -0
- package/build/ts/kcmd/layouts/semantic-model.js +542 -0
- package/build/ts/kcmd/layouts/standard.d.ts +13 -0
- package/build/ts/kcmd/layouts/standard.js +108 -0
- package/build/ts/kcmd/manifest.d.ts +34 -0
- package/build/ts/kcmd/manifest.js +262 -0
- package/build/ts/kcmd/metadata.d.ts +25 -0
- package/build/ts/kcmd/metadata.js +8 -0
- package/build/ts/kcmd/okf/catalog_residue.d.ts +14 -0
- package/build/ts/kcmd/okf/catalog_residue.js +124 -0
- package/build/ts/kcmd/okf/concept.d.ts +14 -0
- package/build/ts/kcmd/okf/concept.js +104 -0
- package/build/ts/kcmd/okf/concept_to_entry.d.ts +8 -0
- package/build/ts/kcmd/okf/concept_to_entry.js +254 -0
- package/build/ts/kcmd/okf/init_okf_workspace.d.ts +15 -0
- package/build/ts/kcmd/okf/init_okf_workspace.js +115 -0
- package/build/ts/kcmd/okf/links.d.ts +23 -0
- package/build/ts/kcmd/okf/links.js +468 -0
- package/build/ts/kcmd/okf/okf_metadata.d.ts +12 -0
- package/build/ts/kcmd/okf/okf_metadata.js +82 -0
- package/build/ts/kcmd/semantic/bigquery.d.ts +22 -0
- package/build/ts/kcmd/semantic/bigquery.js +525 -0
- package/build/ts/kcmd/semantic/binding.d.ts +3 -0
- package/build/ts/kcmd/semantic/binding.js +97 -0
- package/build/ts/kcmd/semantic/catalog_entry.d.ts +24 -0
- package/build/ts/kcmd/semantic/catalog_entry.js +35 -0
- package/build/ts/kcmd/semantic/converters/owl/convert.d.ts +26 -0
- package/build/ts/kcmd/semantic/converters/owl/convert.js +41 -0
- package/build/ts/kcmd/semantic/converters/owl/model.d.ts +98 -0
- package/build/ts/kcmd/semantic/converters/owl/model.js +30 -0
- package/build/ts/kcmd/semantic/converters/owl/parse.d.ts +11 -0
- package/build/ts/kcmd/semantic/converters/owl/parse.js +634 -0
- package/build/ts/kcmd/semantic/converters/owl/to_ir.d.ts +19 -0
- package/build/ts/kcmd/semantic/converters/owl/to_ir.js +390 -0
- package/build/ts/kcmd/semantic/deploy_bigquery.d.ts +20 -0
- package/build/ts/kcmd/semantic/deploy_bigquery.js +226 -0
- package/build/ts/kcmd/semantic/deploy_knowledge_catalog.d.ts +129 -0
- package/build/ts/kcmd/semantic/deploy_knowledge_catalog.js +1396 -0
- package/build/ts/kcmd/semantic/deploy_spanner.d.ts +15 -0
- package/build/ts/kcmd/semantic/deploy_spanner.js +150 -0
- package/build/ts/kcmd/semantic/deployment_target.d.ts +93 -0
- package/build/ts/kcmd/semantic/deployment_target.js +379 -0
- package/build/ts/kcmd/semantic/graph_ddl.d.ts +34 -0
- package/build/ts/kcmd/semantic/graph_ddl.js +563 -0
- package/build/ts/kcmd/semantic/import_model.d.ts +50 -0
- package/build/ts/kcmd/semantic/import_model.js +1275 -0
- package/build/ts/kcmd/semantic/ir.d.ts +589 -0
- package/build/ts/kcmd/semantic/ir.js +247 -0
- package/build/ts/kcmd/semantic/kc_actions.d.ts +45 -0
- package/build/ts/kcmd/semantic/kc_actions.js +531 -0
- package/build/ts/kcmd/semantic/kc_constraints.d.ts +44 -0
- package/build/ts/kcmd/semantic/kc_constraints.js +279 -0
- package/build/ts/kcmd/semantic/kc_converter.d.ts +31 -0
- package/build/ts/kcmd/semantic/kc_converter.js +824 -0
- package/build/ts/kcmd/semantic/kc_custom_types.d.ts +70 -0
- package/build/ts/kcmd/semantic/kc_custom_types.js +828 -0
- package/build/ts/kcmd/semantic/kc_entries.d.ts +155 -0
- package/build/ts/kcmd/semantic/kc_entries.js +284 -0
- package/build/ts/kcmd/semantic/kc_ids.d.ts +103 -0
- package/build/ts/kcmd/semantic/kc_ids.js +191 -0
- package/build/ts/kcmd/semantic/knowledge_catalog.d.ts +32 -0
- package/build/ts/kcmd/semantic/knowledge_catalog.js +1043 -0
- package/build/ts/kcmd/semantic/loader.d.ts +262 -0
- package/build/ts/kcmd/semantic/loader.js +3440 -0
- package/build/ts/kcmd/semantic/names.d.ts +10 -0
- package/build/ts/kcmd/semantic/names.js +85 -0
- package/build/ts/kcmd/semantic/osi_converter.d.ts +60 -0
- package/build/ts/kcmd/semantic/osi_converter.js +911 -0
- package/build/ts/kcmd/semantic/parameters.d.ts +18 -0
- package/build/ts/kcmd/semantic/parameters.js +152 -0
- package/build/ts/kcmd/semantic/pull_kc.d.ts +14 -0
- package/build/ts/kcmd/semantic/pull_kc.js +346 -0
- package/build/ts/kcmd/semantic/resolve_inheritance.d.ts +54 -0
- package/build/ts/kcmd/semantic/resolve_inheritance.js +330 -0
- package/build/ts/kcmd/semantic/resolve_profiles.d.ts +250 -0
- package/build/ts/kcmd/semantic/resolve_profiles.js +1822 -0
- package/build/ts/kcmd/semantic/runtime/agent_tools.d.ts +93 -0
- package/build/ts/kcmd/semantic/runtime/agent_tools.js +243 -0
- package/build/ts/kcmd/semantic/runtime/dialect.d.ts +13 -0
- package/build/ts/kcmd/semantic/runtime/dialect.js +39 -0
- package/build/ts/kcmd/semantic/runtime/runtime.d.ts +94 -0
- package/build/ts/kcmd/semantic/runtime/runtime.js +318 -0
- package/build/ts/kcmd/semantic/runtime/store.d.ts +112 -0
- package/build/ts/kcmd/semantic/runtime/store.js +344 -0
- package/build/ts/kcmd/semantic/skills.d.ts +110 -0
- package/build/ts/kcmd/semantic/skills.js +697 -0
- package/build/ts/kcmd/semantic/source_dialect.d.ts +10 -0
- package/build/ts/kcmd/semantic/source_dialect.js +261 -0
- package/build/ts/kcmd/semantic/source_entries.d.ts +12 -0
- package/build/ts/kcmd/semantic/source_entries.js +282 -0
- package/build/ts/kcmd/semantic/spanner.d.ts +18 -0
- package/build/ts/kcmd/semantic/spanner.js +60 -0
- package/build/ts/kcmd/semantic/sql_expr_utils.d.ts +17 -0
- package/build/ts/kcmd/semantic/sql_expr_utils.js +221 -0
- package/build/ts/kcmd/semantic/sql_identifiers.d.ts +6 -0
- package/build/ts/kcmd/semantic/sql_identifiers.js +267 -0
- package/build/ts/kcmd/semantic/sql_parser.d.ts +44 -0
- package/build/ts/kcmd/semantic/sql_parser.js +378 -0
- package/build/ts/kcmd/semantic/transpile.d.ts +74 -0
- package/build/ts/kcmd/semantic/transpile.js +563 -0
- package/build/ts/kcmd/semantic/validate.d.ts +35 -0
- package/build/ts/kcmd/semantic/validate.js +1899 -0
- package/build/ts/kcmd/semantic/yaml_options.d.ts +6 -0
- package/build/ts/kcmd/semantic/yaml_options.js +58 -0
- package/build/ts/kcmd/semantic/yaml_update.d.ts +26 -0
- package/build/ts/kcmd/semantic/yaml_update.js +782 -0
- package/build/ts/kcmd/snapshot.d.ts +33 -0
- package/build/ts/kcmd/snapshot.js +379 -0
- package/build/ts/kcmd/source.d.ts +31 -0
- package/build/ts/kcmd/source.js +119 -0
- package/build/ts/kcmd/sources/bq-dataset.d.ts +17 -0
- package/build/ts/kcmd/sources/bq-dataset.js +131 -0
- package/build/ts/kcmd/sources/entrygroup.d.ts +21 -0
- package/build/ts/kcmd/sources/entrygroup.js +83 -0
- package/build/ts/kcmd/sources/kb.d.ts +21 -0
- package/build/ts/kcmd/sources/kb.js +82 -0
- package/build/ts/kcmd/sources/semantic-model.d.ts +18 -0
- package/build/ts/kcmd/sources/semantic-model.js +48 -0
- package/build/ts/kcmd/sync.d.ts +35 -0
- package/build/ts/kcmd/sync.js +697 -0
- package/package.json +62 -4
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// Bidirectional conversion between a Dataplex `Entry` and an OKF `Concept`.
|
|
3
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
+
exports.ConceptError = void 0;
|
|
5
|
+
exports.normalizeOkfDocType = normalizeOkfDocType;
|
|
6
|
+
exports.entryToConcept = entryToConcept;
|
|
7
|
+
exports.conceptToEntry = conceptToEntry;
|
|
8
|
+
const catalog_residue_1 = require("./catalog_residue");
|
|
9
|
+
const concept_1 = require("./concept");
|
|
10
|
+
const okf_metadata_1 = require("./okf_metadata");
|
|
11
|
+
class ConceptError extends Error {
|
|
12
|
+
}
|
|
13
|
+
exports.ConceptError = ConceptError;
|
|
14
|
+
function mapping(value) {
|
|
15
|
+
return value && typeof value === 'object' && !Array.isArray(value)
|
|
16
|
+
? value
|
|
17
|
+
: {};
|
|
18
|
+
}
|
|
19
|
+
function text(value) {
|
|
20
|
+
return typeof value === 'string' && value !== '' ? value : undefined;
|
|
21
|
+
}
|
|
22
|
+
function headingTitle(body) {
|
|
23
|
+
for (const line of body.split(/\r?\n/)) {
|
|
24
|
+
const m = line.match(/^#\s+(.+?)\s*$/);
|
|
25
|
+
if (m && m[1])
|
|
26
|
+
return m[1];
|
|
27
|
+
}
|
|
28
|
+
return undefined;
|
|
29
|
+
}
|
|
30
|
+
/** Maps OKF human-readable `type` labels to Dataplex `document.type` slugs. */
|
|
31
|
+
function normalizeOkfDocType(rawType) {
|
|
32
|
+
const norm = rawType
|
|
33
|
+
.trim()
|
|
34
|
+
.toLowerCase()
|
|
35
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
36
|
+
.replace(/^-|-$/g, '');
|
|
37
|
+
if (norm === 'table' ||
|
|
38
|
+
norm === 'bigquery-table' ||
|
|
39
|
+
norm === 'table-context') {
|
|
40
|
+
return 'table-context';
|
|
41
|
+
}
|
|
42
|
+
return norm || 'document';
|
|
43
|
+
}
|
|
44
|
+
function bodyContent(body, hadTrailingNewline) {
|
|
45
|
+
if (hadTrailingNewline)
|
|
46
|
+
return body;
|
|
47
|
+
return body.endsWith('\n') ? body.slice(0, -1) : body;
|
|
48
|
+
}
|
|
49
|
+
function conceptTypeOf(entry) {
|
|
50
|
+
const key = (0, catalog_residue_1.typeFacetKey)(entry.entryType);
|
|
51
|
+
if (key) {
|
|
52
|
+
const label = entry.aspects?.[key]?.data?.['type'];
|
|
53
|
+
if (typeof label === 'string' && label)
|
|
54
|
+
return label;
|
|
55
|
+
}
|
|
56
|
+
return entry.entryType?.split('/').pop() || 'concept';
|
|
57
|
+
}
|
|
58
|
+
function entryToConcept(entry, id) {
|
|
59
|
+
const source = entry.entrySource ?? {};
|
|
60
|
+
const frontmatter = { type: conceptTypeOf(entry) };
|
|
61
|
+
if (source.displayName)
|
|
62
|
+
frontmatter['title'] = source.displayName;
|
|
63
|
+
if (source.description)
|
|
64
|
+
frontmatter['description'] = source.description;
|
|
65
|
+
if (source.resource)
|
|
66
|
+
frontmatter['resource'] = source.resource;
|
|
67
|
+
const overview = entry.aspects?.[catalog_residue_1.OVERVIEW_ASPECT_KEY];
|
|
68
|
+
const content = typeof overview?.data?.['content'] === 'string'
|
|
69
|
+
? overview.data['content']
|
|
70
|
+
: '';
|
|
71
|
+
const { body, metadata } = (0, okf_metadata_1.splitOkfMetadata)(content);
|
|
72
|
+
Object.assign(frontmatter, metadata);
|
|
73
|
+
const residue = (0, catalog_residue_1.buildResidue)(entry, catalog_residue_1.OVERVIEW_ASPECT_KEY, body);
|
|
74
|
+
if (residue)
|
|
75
|
+
frontmatter[concept_1.RESIDUE_KEY] = residue;
|
|
76
|
+
(0, catalog_residue_1.assertResidueOnly)(frontmatter);
|
|
77
|
+
return { id, frontmatter, body };
|
|
78
|
+
}
|
|
79
|
+
function conceptToEntry(concept, entryGroup) {
|
|
80
|
+
const frontmatter = concept.frontmatter;
|
|
81
|
+
(0, catalog_residue_1.assertResidueOnly)(frontmatter);
|
|
82
|
+
const residue = mapping(frontmatter[concept_1.RESIDUE_KEY]);
|
|
83
|
+
const extra = mapping(frontmatter[concept_1.EXTRA_KEY]);
|
|
84
|
+
const extraResource = mapping(extra['resource']);
|
|
85
|
+
const residueEntryType = text(residue['entryType']);
|
|
86
|
+
const extraEntryType = text(extra['type']);
|
|
87
|
+
const rawExplicitType = residueEntryType ?? extraEntryType;
|
|
88
|
+
const hasQueryTemplateAspect = catalog_residue_1.QUERY_TEMPLATE_ASPECT_KEY in mapping(extra['aspects']) ||
|
|
89
|
+
catalog_residue_1.QUERY_TEMPLATE_ASPECT_KEY in mapping(residue['aspects']);
|
|
90
|
+
const inferredQueryTemplateType = !rawExplicitType &&
|
|
91
|
+
hasQueryTemplateAspect &&
|
|
92
|
+
normalizeOkfDocType(text(frontmatter['type']) ?? '') === 'query-template'
|
|
93
|
+
? catalog_residue_1.QUERY_TEMPLATE_ENTRY_TYPE
|
|
94
|
+
: undefined;
|
|
95
|
+
const normalizedExplicitType = rawExplicitType ?? inferredQueryTemplateType;
|
|
96
|
+
const isQueryTemplate = Boolean(normalizedExplicitType?.endsWith('/entryTypes/query-template'));
|
|
97
|
+
const defaultedEntryType = !normalizedExplicitType;
|
|
98
|
+
const isRootIndex = concept.id === 'index';
|
|
99
|
+
const isDirIndex = concept.id.endsWith('/index');
|
|
100
|
+
let conceptType = text(frontmatter['type']);
|
|
101
|
+
if (!conceptType && defaultedEntryType) {
|
|
102
|
+
if (isRootIndex) {
|
|
103
|
+
conceptType = 'knowledge-base';
|
|
104
|
+
}
|
|
105
|
+
else if (isDirIndex) {
|
|
106
|
+
conceptType = 'knowledge-base-index';
|
|
107
|
+
}
|
|
108
|
+
else {
|
|
109
|
+
throw new ConceptError(`${concept.id}: no ${concept_1.RESIDUE_KEY}.entryType and no frontmatter 'type', ` +
|
|
110
|
+
`so the catalog entry type is unknown`);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
const entryType = normalizedExplicitType ?? catalog_residue_1.DEFAULT_DOCUMENT_ENTRY_TYPE;
|
|
114
|
+
let resolvedId = text(residue['entryId']) ?? text(extra['entry_id']) ?? concept.id;
|
|
115
|
+
if (defaultedEntryType &&
|
|
116
|
+
!text(residue['entryId']) &&
|
|
117
|
+
!text(extra['entry_id'])) {
|
|
118
|
+
if (isRootIndex) {
|
|
119
|
+
resolvedId = 'agents';
|
|
120
|
+
}
|
|
121
|
+
else if (isDirIndex) {
|
|
122
|
+
resolvedId = concept.id.slice(0, -'/index'.length);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
const entry = {
|
|
126
|
+
name: `${entryGroup}/entries/${resolvedId}`,
|
|
127
|
+
entryType,
|
|
128
|
+
};
|
|
129
|
+
const explicitParent = text(residue['parentEntry']) ?? text(extraResource['parent']);
|
|
130
|
+
if (explicitParent) {
|
|
131
|
+
entry.parentEntry = explicitParent;
|
|
132
|
+
}
|
|
133
|
+
else if (defaultedEntryType) {
|
|
134
|
+
if (isRootIndex) {
|
|
135
|
+
// Root `index.md` (`agents`) is the top-level entry; no parentEntry.
|
|
136
|
+
}
|
|
137
|
+
else if (isDirIndex) {
|
|
138
|
+
const slash = resolvedId.lastIndexOf('/');
|
|
139
|
+
entry.parentEntry =
|
|
140
|
+
slash !== -1
|
|
141
|
+
? `${entryGroup}/entries/${resolvedId.slice(0, slash)}`
|
|
142
|
+
: `${entryGroup}/entries/agents`;
|
|
143
|
+
}
|
|
144
|
+
else {
|
|
145
|
+
const slash = resolvedId.lastIndexOf('/');
|
|
146
|
+
if (slash !== -1) {
|
|
147
|
+
entry.parentEntry = `${entryGroup}/entries/${resolvedId.slice(0, slash)}`;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
const source = { ...mapping(residue['entrySource']) };
|
|
152
|
+
for (const key of ['system', 'platform', 'location', 'ancestors', 'labels']) {
|
|
153
|
+
if (source[key] === undefined && extraResource[key] !== undefined) {
|
|
154
|
+
source[key] = extraResource[key];
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
const displayName = text(frontmatter['title']) ??
|
|
158
|
+
(defaultedEntryType || isQueryTemplate
|
|
159
|
+
? headingTitle(concept.body)
|
|
160
|
+
: undefined);
|
|
161
|
+
const description = text(frontmatter['description']);
|
|
162
|
+
const resource = text(frontmatter['resource']);
|
|
163
|
+
if (displayName)
|
|
164
|
+
source['displayName'] = displayName;
|
|
165
|
+
if (description)
|
|
166
|
+
source['description'] = description;
|
|
167
|
+
if (resource)
|
|
168
|
+
source['resource'] = resource;
|
|
169
|
+
if (Object.keys(source).length) {
|
|
170
|
+
entry.entrySource = source;
|
|
171
|
+
}
|
|
172
|
+
const aspects = {};
|
|
173
|
+
for (const [key, data] of Object.entries(mapping(extra['aspects']))) {
|
|
174
|
+
const mapped = mapping(data);
|
|
175
|
+
const inner = Object.keys(mapped).length === 1 && 'data' in mapped
|
|
176
|
+
? mapping(mapped['data'])
|
|
177
|
+
: mapped;
|
|
178
|
+
aspects[key] = { data: { ...inner } };
|
|
179
|
+
}
|
|
180
|
+
for (const [key, data] of Object.entries(mapping(residue['aspects']))) {
|
|
181
|
+
aspects[key] = { data: { ...mapping(data) } };
|
|
182
|
+
}
|
|
183
|
+
// A type with no stashed aspect was read off the entry type, not an aspect,
|
|
184
|
+
// unless the entry came from a pure OKF file (defaultedEntryType) or `extra`.
|
|
185
|
+
const facetKey = (0, catalog_residue_1.typeFacetKey)(entryType);
|
|
186
|
+
const shortEntryType = entryType.split('/').pop();
|
|
187
|
+
if (isQueryTemplate) {
|
|
188
|
+
const qtAspect = aspects[catalog_residue_1.QUERY_TEMPLATE_ASPECT_KEY];
|
|
189
|
+
if (!qtAspect) {
|
|
190
|
+
throw new ConceptError(`${concept.id}: query-template entry requires aspect '${catalog_residue_1.QUERY_TEMPLATE_ASPECT_KEY}'`);
|
|
191
|
+
}
|
|
192
|
+
const qtData = qtAspect.data;
|
|
193
|
+
for (const reqField of ['query', 'nlQuery', 'intent', 'sourceType']) {
|
|
194
|
+
if (!text(qtData[reqField])) {
|
|
195
|
+
throw new ConceptError(`${concept.id}: ${catalog_residue_1.QUERY_TEMPLATE_ASPECT_KEY}.${reqField} is required`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
if (Array.isArray(qtData['parameters'])) {
|
|
199
|
+
const allowedParamKeys = new Set([
|
|
200
|
+
'name',
|
|
201
|
+
'type',
|
|
202
|
+
'description',
|
|
203
|
+
'sampleValues',
|
|
204
|
+
'targets',
|
|
205
|
+
]);
|
|
206
|
+
qtData['parameters'] = qtData['parameters'].map((rawParam, idx) => {
|
|
207
|
+
const param = mapping(rawParam);
|
|
208
|
+
const cleaned = {};
|
|
209
|
+
const stripped = [];
|
|
210
|
+
for (const [k, v] of Object.entries(param)) {
|
|
211
|
+
if (allowedParamKeys.has(k)) {
|
|
212
|
+
cleaned[k] = v;
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
stripped.push(k);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (stripped.length) {
|
|
219
|
+
console.warn(`[kcmd] ${concept.id}: stripping unsupported parameter key(s) ${stripped.join(', ')} on parameters[${idx}]`);
|
|
220
|
+
}
|
|
221
|
+
return cleaned;
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
delete aspects[catalog_residue_1.DOCUMENT_ASPECT_KEY];
|
|
225
|
+
}
|
|
226
|
+
else if (defaultedEntryType) {
|
|
227
|
+
const docType = normalizeOkfDocType(conceptType ?? 'document');
|
|
228
|
+
aspects[catalog_residue_1.DOCUMENT_ASPECT_KEY] = {
|
|
229
|
+
data: { type: docType, ...(aspects[catalog_residue_1.DOCUMENT_ASPECT_KEY]?.data ?? {}) },
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
else if (conceptType &&
|
|
233
|
+
facetKey &&
|
|
234
|
+
facetKey in aspects &&
|
|
235
|
+
(facetKey === catalog_residue_1.DOCUMENT_ASPECT_KEY ||
|
|
236
|
+
normalizeOkfDocType(conceptType) !== shortEntryType)) {
|
|
237
|
+
aspects[facetKey] = { data: { type: conceptType, ...aspects[facetKey].data } };
|
|
238
|
+
}
|
|
239
|
+
else if (conceptType &&
|
|
240
|
+
!residueEntryType &&
|
|
241
|
+
extraEntryType &&
|
|
242
|
+
facetKey === catalog_residue_1.DOCUMENT_ASPECT_KEY &&
|
|
243
|
+
!(facetKey in aspects)) {
|
|
244
|
+
aspects[facetKey] = { data: { type: normalizeOkfDocType(conceptType) } };
|
|
245
|
+
}
|
|
246
|
+
const content = (0, okf_metadata_1.appendOkfMetadata)(bodyContent(concept.body, residue['trailingNewline'] !== false), frontmatter);
|
|
247
|
+
if (content) {
|
|
248
|
+
aspects[catalog_residue_1.OVERVIEW_ASPECT_KEY] = { data: { content, contentType: 'MARKDOWN' } };
|
|
249
|
+
}
|
|
250
|
+
if (Object.keys(aspects).length) {
|
|
251
|
+
entry.aspects = aspects;
|
|
252
|
+
}
|
|
253
|
+
return entry;
|
|
254
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as gcp from '../gcp';
|
|
2
|
+
import { CatalogManifest } from '../manifest';
|
|
3
|
+
/** Options forwarded from `kcmd init`. */
|
|
4
|
+
export interface InitOkfWorkspaceOptions {
|
|
5
|
+
/** Pull the context set straight after scaffolding. */
|
|
6
|
+
pull?: boolean;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Scaffolds an OKF workspace for the given scope: `catalog.yaml` at the root,
|
|
10
|
+
* and beside it a `bundle/` directory (pulling existing concepts if the
|
|
11
|
+
* EntryGroup exists remotely and `--pull` is requested or `okfRemoteExists` is set).
|
|
12
|
+
*
|
|
13
|
+
* @returns a process exit code: 0 on success, non-zero on failure.
|
|
14
|
+
*/
|
|
15
|
+
export declare function initOkfWorkspace(ctx: gcp.ApiContext, manifest: CatalogManifest, options?: InitOkfWorkspaceOptions): Promise<number>;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
// The `kcmd init --format=okf` path: scaffold an OKF workspace.
|
|
3
|
+
//
|
|
4
|
+
// Writes `catalog.yaml` (`scope: entryGroup.<project>.<location>.<id>` and
|
|
5
|
+
// `layout: okf`, which `kcmd pull` and `kcmd push` read to take the OKF path)
|
|
6
|
+
// and a `bundle/index.md` root skeleton. If `--pull` is set (or the entry group
|
|
7
|
+
// already exists remotely via `init`), pulls the remote entries into `bundle/`.
|
|
8
|
+
// When the entry group does not exist yet, it is left uncreated until `kcmd push`
|
|
9
|
+
// (so plan/review gates hold before any remote mutation).
|
|
10
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
11
|
+
if (k2 === undefined) k2 = k;
|
|
12
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
13
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
14
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
15
|
+
}
|
|
16
|
+
Object.defineProperty(o, k2, desc);
|
|
17
|
+
}) : (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
o[k2] = m[k];
|
|
20
|
+
}));
|
|
21
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
22
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
23
|
+
}) : function(o, v) {
|
|
24
|
+
o["default"] = v;
|
|
25
|
+
});
|
|
26
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
27
|
+
var ownKeys = function(o) {
|
|
28
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
29
|
+
var ar = [];
|
|
30
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
31
|
+
return ar;
|
|
32
|
+
};
|
|
33
|
+
return ownKeys(o);
|
|
34
|
+
};
|
|
35
|
+
return function (mod) {
|
|
36
|
+
if (mod && mod.__esModule) return mod;
|
|
37
|
+
var result = {};
|
|
38
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
39
|
+
__setModuleDefault(result, mod);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
})();
|
|
43
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
44
|
+
exports.initOkfWorkspace = initOkfWorkspace;
|
|
45
|
+
const fs = __importStar(require("node:fs"));
|
|
46
|
+
const path = __importStar(require("node:path"));
|
|
47
|
+
const yaml = __importStar(require("yaml"));
|
|
48
|
+
const dataplex = __importStar(require("../gcp/dataplex"));
|
|
49
|
+
const okf_1 = require("../layouts/okf");
|
|
50
|
+
const manifest_1 = require("../manifest");
|
|
51
|
+
const snapshot_1 = require("../snapshot");
|
|
52
|
+
const sync_1 = require("../sync");
|
|
53
|
+
function scopeOf(text) {
|
|
54
|
+
try {
|
|
55
|
+
return JSON.stringify(yaml.parse(text)?.scope);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return undefined;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Scaffolds an OKF workspace for the given scope: `catalog.yaml` at the root,
|
|
63
|
+
* and beside it a `bundle/` directory (pulling existing concepts if the
|
|
64
|
+
* EntryGroup exists remotely and `--pull` is requested or `okfRemoteExists` is set).
|
|
65
|
+
*
|
|
66
|
+
* @returns a process exit code: 0 on success, non-zero on failure.
|
|
67
|
+
*/
|
|
68
|
+
async function initOkfWorkspace(ctx, manifest, options = {}) {
|
|
69
|
+
const scopeName = manifest?.source?.name ?? '';
|
|
70
|
+
const parts = scopeName.split('.');
|
|
71
|
+
if (parts.length !== 3 || parts.some((p) => !p)) {
|
|
72
|
+
console.error(`Error: EntryGroup must be in format <projectId>.<locationId>.<entryGroupId>: '${scopeName}'`);
|
|
73
|
+
return 1;
|
|
74
|
+
}
|
|
75
|
+
const [, , groupId] = parts;
|
|
76
|
+
const prior = fs.existsSync('catalog.yaml')
|
|
77
|
+
? fs.readFileSync('catalog.yaml', 'utf8')
|
|
78
|
+
: undefined;
|
|
79
|
+
if (typeof manifest.save === 'function') {
|
|
80
|
+
manifest.save('catalog.yaml');
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
const scopeType = manifest.source.type || 'entryGroup';
|
|
84
|
+
fs.writeFileSync('catalog.yaml', yaml.stringify({ scope: `${scopeType}.${scopeName}` }), 'utf8');
|
|
85
|
+
}
|
|
86
|
+
const scope = scopeOf(fs.readFileSync('catalog.yaml', 'utf8'));
|
|
87
|
+
if (prior !== undefined && scope !== undefined && scopeOf(prior) === scope) {
|
|
88
|
+
fs.writeFileSync('catalog.yaml', prior);
|
|
89
|
+
}
|
|
90
|
+
(0, manifest_1.writeWorkspaceLayout)('catalog.yaml', 'okf');
|
|
91
|
+
console.log(fs.readFileSync('catalog.yaml', 'utf8').trimEnd());
|
|
92
|
+
const remoteExists = manifest.okfRemoteExists === true;
|
|
93
|
+
const shouldPull = (options.pull && remoteExists) ||
|
|
94
|
+
(remoteExists && options.pull === undefined);
|
|
95
|
+
if (shouldPull) {
|
|
96
|
+
const snapshot = await snapshot_1.CatalogSnapshot.fromPath('.', ctx);
|
|
97
|
+
const sync = new sync_1.CatalogSync(new dataplex.CatalogClient(ctx), snapshot);
|
|
98
|
+
const result = await sync.pull({ dryRun: false });
|
|
99
|
+
if (!result.success) {
|
|
100
|
+
if (result.details)
|
|
101
|
+
console.error(`Error: ${result.details}`);
|
|
102
|
+
return 1;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
console.log(`Initialized OKF workspace for ${scopeName} in ${okf_1.BUNDLE_DIR}/ (entry group does not exist yet; \`kcmd push\` creates it).`);
|
|
107
|
+
}
|
|
108
|
+
fs.mkdirSync(okf_1.BUNDLE_DIR, { recursive: true });
|
|
109
|
+
const indexPath = path.join(okf_1.BUNDLE_DIR, 'index.md');
|
|
110
|
+
const agentsPath = path.join(okf_1.BUNDLE_DIR, 'agents.md');
|
|
111
|
+
if (!fs.existsSync(indexPath) && !fs.existsSync(agentsPath)) {
|
|
112
|
+
fs.writeFileSync(indexPath, `---\nokf_version: "0.2"\n---\n# ${groupId}\n`, 'utf8');
|
|
113
|
+
}
|
|
114
|
+
return 0;
|
|
115
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import * as gcp from '../gcp';
|
|
2
|
+
import { Concept } from './concept';
|
|
3
|
+
export declare const LINKS_FILE = "_links.yaml";
|
|
4
|
+
export interface BundleLinksResult {
|
|
5
|
+
/** True when `_links.yaml` exists or a concept declares frontmatter links. */
|
|
6
|
+
hasLinksConfig: boolean;
|
|
7
|
+
/** Deduplicated Dataplex EntryLinks ready for push. */
|
|
8
|
+
links: gcp.EntryLink[];
|
|
9
|
+
}
|
|
10
|
+
/** Reads `bundle/_links.yaml` and any frontmatter `links` from `concepts`. */
|
|
11
|
+
export declare function readBundleLinks(root: string, entryGroup: string, concepts?: Concept[]): BundleLinksResult;
|
|
12
|
+
/** Formats Dataplex `EntryLink`s into canonical `bundle/_links.yaml` content. */
|
|
13
|
+
export declare function formatLinksYaml(links: gcp.EntryLink[], entryGroup: string): string;
|
|
14
|
+
/** Extracts the bare `entryLinkId` from an `EntryLink.name`. */
|
|
15
|
+
export declare function entryLinkId(link: gcp.EntryLink): string;
|
|
16
|
+
/** Deterministic deduplication key across link type and endpoints. */
|
|
17
|
+
export declare function linkDedupKey(link: gcp.EntryLink): string;
|
|
18
|
+
/** True when `existing` differs from `desired` in immutable type or references. */
|
|
19
|
+
export declare function isStaleEntryLink(existing: gcp.EntryLink, desired: gcp.EntryLink): boolean;
|
|
20
|
+
export declare function resolveEntryLinkType(rawType: string): string;
|
|
21
|
+
export declare function shortenLinkType(entryLinkType: string): string;
|
|
22
|
+
export declare function resolveEntryRefName(rawName: string, entryGroup: string): string;
|
|
23
|
+
export declare function shortenEntryName(fullEntryName: string, entryGroup: string): string;
|