@kweaver-ai/kweaver-sdk 0.5.1 β†’ 0.6.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.
Files changed (95) hide show
  1. package/README.md +25 -2
  2. package/README.zh.md +24 -1
  3. package/dist/api/agent-chat.d.ts +8 -2
  4. package/dist/api/agent-chat.js +150 -44
  5. package/dist/api/agent-list.d.ts +35 -0
  6. package/dist/api/agent-list.js +95 -21
  7. package/dist/api/bkn-backend.d.ts +60 -0
  8. package/dist/api/bkn-backend.js +103 -10
  9. package/dist/api/business-domains.js +9 -5
  10. package/dist/api/context-loader.js +4 -1
  11. package/dist/api/conversations.d.ts +6 -3
  12. package/dist/api/conversations.js +29 -35
  13. package/dist/api/dataflow.js +1 -10
  14. package/dist/api/dataflow2.d.ts +95 -0
  15. package/dist/api/dataflow2.js +80 -0
  16. package/dist/api/datasources.js +1 -10
  17. package/dist/api/dataviews.js +1 -10
  18. package/dist/api/headers.d.ts +11 -0
  19. package/dist/api/headers.js +30 -0
  20. package/dist/api/knowledge-networks.d.ts +41 -0
  21. package/dist/api/knowledge-networks.js +69 -22
  22. package/dist/api/ontology-query.d.ts +14 -1
  23. package/dist/api/ontology-query.js +63 -49
  24. package/dist/api/semantic-search.js +2 -12
  25. package/dist/api/skills.d.ts +141 -0
  26. package/dist/api/skills.js +208 -0
  27. package/dist/api/vega.d.ts +54 -7
  28. package/dist/api/vega.js +112 -25
  29. package/dist/auth/oauth.d.ts +5 -1
  30. package/dist/auth/oauth.js +351 -95
  31. package/dist/cli.js +49 -5
  32. package/dist/client.d.ts +12 -0
  33. package/dist/client.js +52 -8
  34. package/dist/commands/agent.d.ts +33 -1
  35. package/dist/commands/agent.js +721 -49
  36. package/dist/commands/auth.js +226 -55
  37. package/dist/commands/bkn-ops.d.ts +77 -0
  38. package/dist/commands/bkn-ops.js +1056 -0
  39. package/dist/commands/bkn-query.d.ts +14 -0
  40. package/dist/commands/bkn-query.js +370 -0
  41. package/dist/commands/bkn-schema.d.ts +135 -0
  42. package/dist/commands/bkn-schema.js +1483 -0
  43. package/dist/commands/bkn-utils.d.ts +36 -0
  44. package/dist/commands/bkn-utils.js +102 -0
  45. package/dist/commands/bkn.d.ts +7 -113
  46. package/dist/commands/bkn.js +175 -2429
  47. package/dist/commands/call.js +8 -5
  48. package/dist/commands/dataflow.d.ts +1 -0
  49. package/dist/commands/dataflow.js +251 -0
  50. package/dist/commands/dataview.d.ts +7 -0
  51. package/dist/commands/dataview.js +38 -2
  52. package/dist/commands/ds.d.ts +1 -0
  53. package/dist/commands/ds.js +8 -1
  54. package/dist/commands/explore-bkn.d.ts +79 -0
  55. package/dist/commands/explore-bkn.js +273 -0
  56. package/dist/commands/explore-chat.d.ts +3 -0
  57. package/dist/commands/explore-chat.js +193 -0
  58. package/dist/commands/explore-vega.d.ts +3 -0
  59. package/dist/commands/explore-vega.js +71 -0
  60. package/dist/commands/explore.d.ts +9 -0
  61. package/dist/commands/explore.js +258 -0
  62. package/dist/commands/import-csv.d.ts +2 -0
  63. package/dist/commands/import-csv.js +3 -2
  64. package/dist/commands/skill.d.ts +26 -0
  65. package/dist/commands/skill.js +524 -0
  66. package/dist/commands/vega.js +372 -117
  67. package/dist/config/jwt.d.ts +6 -0
  68. package/dist/config/jwt.js +21 -0
  69. package/dist/config/no-auth.d.ts +3 -0
  70. package/dist/config/no-auth.js +5 -0
  71. package/dist/config/store.d.ts +45 -5
  72. package/dist/config/store.js +385 -30
  73. package/dist/index.d.ts +6 -1
  74. package/dist/index.js +5 -1
  75. package/dist/kweaver.d.ts +5 -0
  76. package/dist/kweaver.js +32 -2
  77. package/dist/resources/bkn.d.ts +4 -0
  78. package/dist/resources/bkn.js +6 -3
  79. package/dist/resources/conversations.d.ts +5 -2
  80. package/dist/resources/conversations.js +17 -3
  81. package/dist/resources/knowledge-networks.js +3 -8
  82. package/dist/resources/skills.d.ts +47 -0
  83. package/dist/resources/skills.js +47 -0
  84. package/dist/resources/vega.d.ts +11 -6
  85. package/dist/resources/vega.js +37 -10
  86. package/dist/templates/explorer/app.js +136 -0
  87. package/dist/templates/explorer/bkn.js +747 -0
  88. package/dist/templates/explorer/chat.js +980 -0
  89. package/dist/templates/explorer/dashboard.js +82 -0
  90. package/dist/templates/explorer/index.html +35 -0
  91. package/dist/templates/explorer/style.css +2440 -0
  92. package/dist/templates/explorer/vega.js +291 -0
  93. package/dist/utils/http.d.ts +3 -0
  94. package/dist/utils/http.js +37 -1
  95. package/package.json +9 -5
package/dist/kweaver.js CHANGED
@@ -41,8 +41,25 @@ export function configure(opts) {
41
41
  _client = null;
42
42
  _defaultBknId = null;
43
43
  _defaultAgentId = null;
44
- const { bknId, agentId, businessDomain, config, baseUrl, accessToken } = opts;
45
- if (config) {
44
+ const { bknId, agentId, businessDomain, config, baseUrl, accessToken, auth } = opts;
45
+ if (auth === false && config) {
46
+ throw new Error("Cannot use auth: false with config: true.");
47
+ }
48
+ if (auth === false && accessToken) {
49
+ throw new Error("Cannot use auth: false with accessToken.");
50
+ }
51
+ if (auth === false) {
52
+ const resolvedBase = baseUrl ?? process.env.KWEAVER_BASE_URL;
53
+ if (!resolvedBase) {
54
+ throw new Error("Provide baseUrl= or set KWEAVER_BASE_URL when auth is false.");
55
+ }
56
+ _client = new KWeaverClient({
57
+ baseUrl: resolvedBase,
58
+ auth: false,
59
+ businessDomain,
60
+ });
61
+ }
62
+ else if (config) {
46
63
  // Use saved credentials β€” do NOT pass baseUrl to avoid cross-env leaks
47
64
  const platform = getCurrentPlatform();
48
65
  if (!platform) {
@@ -58,6 +75,19 @@ export function configure(opts) {
58
75
  businessDomain,
59
76
  });
60
77
  }
78
+ else if (!accessToken &&
79
+ !process.env.KWEAVER_TOKEN &&
80
+ ["1", "true", "yes"].includes((process.env.KWEAVER_NO_AUTH ?? "").toLowerCase())) {
81
+ const resolvedBase = baseUrl ?? process.env.KWEAVER_BASE_URL;
82
+ if (!resolvedBase) {
83
+ throw new Error("Provide baseUrl= or set KWEAVER_BASE_URL when KWEAVER_NO_AUTH is set.");
84
+ }
85
+ _client = new KWeaverClient({
86
+ baseUrl: resolvedBase,
87
+ auth: false,
88
+ businessDomain,
89
+ });
90
+ }
61
91
  else {
62
92
  if (!baseUrl && !process.env.KWEAVER_BASE_URL) {
63
93
  throw new Error("Provide baseUrl=, config=true, or set KWEAVER_BASE_URL.");
@@ -32,6 +32,10 @@ export declare class BknResource {
32
32
  queryProperties(knId: string, otId: string, body: Record<string, unknown>): Promise<unknown>;
33
33
  querySubgraph(knId: string, body: Record<string, unknown>): Promise<unknown>;
34
34
  queryAction(knId: string, atId: string, body: Record<string, unknown>): Promise<unknown>;
35
+ /**
36
+ * Execute an action type (has side effects).
37
+ * @param body - Must include `_instance_identities`: `[{"<primary_key>": "<value>"}]`
38
+ */
35
39
  executeAction(knId: string, atId: string, body: Record<string, unknown>): Promise<unknown>;
36
40
  getExecution(knId: string, executionId: string): Promise<unknown>;
37
41
  listActionLogs(knId: string, opts?: {
@@ -1,3 +1,4 @@
1
+ import { buildHeaders } from "../api/headers.js";
1
2
  import { objectTypeQuery, objectTypeProperties, subgraph, actionTypeQuery, actionTypeExecute, actionExecutionGet, actionLogsList, actionLogGet, actionLogCancel, } from "../api/ontology-query.js";
2
3
  import { fetchTextOrThrow } from "../utils/http.js";
3
4
  /** BKN engine resource β€” instance queries, subgraph, action execution and logs. */
@@ -21,9 +22,7 @@ export class BknResource {
21
22
  method: "POST",
22
23
  headers: {
23
24
  "content-type": "application/json",
24
- authorization: `Bearer ${accessToken}`,
25
- token: accessToken,
26
- "x-business-domain": businessDomain,
25
+ ...buildHeaders(accessToken, businessDomain),
27
26
  },
28
27
  body: JSON.stringify({
29
28
  kn_id: bknId,
@@ -57,6 +56,10 @@ export class BknResource {
57
56
  const raw = await actionTypeQuery({ ...this.ctx.base(), knId, atId, body: JSON.stringify(body) });
58
57
  return JSON.parse(raw);
59
58
  }
59
+ /**
60
+ * Execute an action type (has side effects).
61
+ * @param body - Must include `_instance_identities`: `[{"<primary_key>": "<value>"}]`
62
+ */
60
63
  async executeAction(knId, atId, body) {
61
64
  const raw = await actionTypeExecute({ ...this.ctx.base(), knId, atId, body: JSON.stringify(body) });
62
65
  return JSON.parse(raw);
@@ -4,8 +4,11 @@ export declare class ConversationsResource {
4
4
  constructor(ctx: ClientContext);
5
5
  list(agentId: string, opts?: {
6
6
  limit?: number;
7
+ page?: number;
8
+ size?: number;
9
+ version?: string;
7
10
  }): Promise<unknown[]>;
8
- listMessages(conversationId: string, opts?: {
9
- limit?: number;
11
+ listMessages(agentId: string, conversationId: string, opts?: {
12
+ version?: string;
10
13
  }): Promise<unknown[]>;
11
14
  }
@@ -1,16 +1,30 @@
1
1
  import { listConversations, listMessages } from "../api/conversations.js";
2
+ import { fetchAgentInfo } from "../api/agent-chat.js";
2
3
  export class ConversationsResource {
3
4
  ctx;
4
5
  constructor(ctx) {
5
6
  this.ctx = ctx;
6
7
  }
7
8
  async list(agentId, opts = {}) {
8
- const raw = await listConversations({ ...this.ctx.base(), agentId, ...opts });
9
+ const { version = "v0", limit, page, size } = opts;
10
+ const info = await fetchAgentInfo({ ...this.ctx.base(), agentId, version });
11
+ const raw = await listConversations({
12
+ ...this.ctx.base(),
13
+ agentKey: info.key,
14
+ page: page ?? 1,
15
+ size: size ?? (limit ?? 10),
16
+ });
9
17
  const parsed = JSON.parse(raw);
10
18
  return Array.isArray(parsed) ? parsed : [];
11
19
  }
12
- async listMessages(conversationId, opts = {}) {
13
- const raw = await listMessages({ ...this.ctx.base(), conversationId, ...opts });
20
+ async listMessages(agentId, conversationId, opts = {}) {
21
+ const { version = "v0" } = opts;
22
+ const info = await fetchAgentInfo({ ...this.ctx.base(), agentId, version });
23
+ const raw = await listMessages({
24
+ ...this.ctx.base(),
25
+ agentKey: info.key,
26
+ conversationId,
27
+ });
14
28
  const parsed = JSON.parse(raw);
15
29
  return Array.isArray(parsed) ? parsed : [];
16
30
  }
@@ -1,3 +1,4 @@
1
+ import { buildHeaders } from "../api/headers.js";
1
2
  import { listKnowledgeNetworks, getKnowledgeNetwork, createKnowledgeNetwork, updateKnowledgeNetwork, deleteKnowledgeNetwork, listObjectTypes, listRelationTypes, listActionTypes, } from "../api/knowledge-networks.js";
2
3
  import { fetchTextOrThrow } from "../utils/http.js";
3
4
  export class KnowledgeNetworksResource {
@@ -69,9 +70,7 @@ export class KnowledgeNetworksResource {
69
70
  const { baseUrl, accessToken, businessDomain } = this.ctx.base();
70
71
  const headers = {
71
72
  "content-type": "application/json",
72
- authorization: `Bearer ${accessToken}`,
73
- token: accessToken,
74
- "x-business-domain": businessDomain,
73
+ ...buildHeaders(accessToken, businessDomain),
75
74
  };
76
75
  await fetchTextOrThrow(`${baseUrl}/api/ontology-manager/v1/knowledge-networks/${encodeURIComponent(bknId)}/jobs`, {
77
76
  method: "POST",
@@ -82,11 +81,7 @@ export class KnowledgeNetworksResource {
82
81
  /** Poll build status for a BKN. */
83
82
  async buildStatus(bknId) {
84
83
  const { baseUrl, accessToken, businessDomain } = this.ctx.base();
85
- const headers = {
86
- authorization: `Bearer ${accessToken}`,
87
- token: accessToken,
88
- "x-business-domain": businessDomain,
89
- };
84
+ const headers = buildHeaders(accessToken, businessDomain);
90
85
  const { body } = await fetchTextOrThrow(`${baseUrl}/api/ontology-manager/v1/knowledge-networks/${encodeURIComponent(bknId)}/jobs?limit=1&direction=desc`, { headers });
91
86
  const data = JSON.parse(body);
92
87
  const jobs = Array.isArray(data)
@@ -0,0 +1,47 @@
1
+ import type { ClientContext } from "../client.js";
2
+ import { type SkillListResult, type SkillStatus } from "../api/skills.js";
3
+ export declare class SkillsResource {
4
+ private readonly ctx;
5
+ constructor(ctx: ClientContext);
6
+ list(opts?: {
7
+ page?: number;
8
+ pageSize?: number;
9
+ sortBy?: "create_time" | "update_time" | "name";
10
+ sortOrder?: "asc" | "desc";
11
+ all?: boolean;
12
+ name?: string;
13
+ status?: SkillStatus;
14
+ source?: string;
15
+ createUser?: string;
16
+ }): Promise<SkillListResult>;
17
+ market(opts?: {
18
+ page?: number;
19
+ pageSize?: number;
20
+ sortBy?: "create_time" | "update_time" | "name";
21
+ sortOrder?: "asc" | "desc";
22
+ all?: boolean;
23
+ name?: string;
24
+ source?: string;
25
+ }): Promise<SkillListResult>;
26
+ get(skillId: string): Promise<import("../api/skills.js").SkillInfo>;
27
+ registerContent(content: string, opts?: {
28
+ source?: string;
29
+ extendInfo?: Record<string, unknown>;
30
+ }): Promise<import("../api/skills.js").RegisterSkillResult>;
31
+ registerZip(filename: string, bytes: Uint8Array, opts?: {
32
+ source?: string;
33
+ extendInfo?: Record<string, unknown>;
34
+ }): Promise<import("../api/skills.js").RegisterSkillResult>;
35
+ delete(skillId: string): Promise<import("../api/skills.js").DeleteSkillResult>;
36
+ updateStatus(skillId: string, status: SkillStatus): Promise<import("../api/skills.js").UpdateSkillStatusResult>;
37
+ content(skillId: string): Promise<import("../api/skills.js").SkillContentIndex>;
38
+ fetchContent(skillId: string): Promise<string>;
39
+ readFile(skillId: string, relPath: string): Promise<import("../api/skills.js").SkillFileReadResult>;
40
+ fetchFile(skillId: string, relPath: string): Promise<Uint8Array<ArrayBufferLike>>;
41
+ download(skillId: string): Promise<import("../api/skills.js").DownloadedSkillArchive>;
42
+ install(skillId: string, directory: string, opts?: {
43
+ force?: boolean;
44
+ }): Promise<{
45
+ directory: string;
46
+ }>;
47
+ }
@@ -0,0 +1,47 @@
1
+ import { deleteSkill, downloadSkill, fetchSkillContent, fetchSkillFile, getSkill, getSkillContentIndex, installSkillArchive, listSkillMarket, listSkills, readSkillFile, registerSkillContent, registerSkillZip, updateSkillStatus, } from "../api/skills.js";
2
+ export class SkillsResource {
3
+ ctx;
4
+ constructor(ctx) {
5
+ this.ctx = ctx;
6
+ }
7
+ async list(opts = {}) {
8
+ return listSkills({ ...this.ctx.base(), pageSize: 30, ...opts });
9
+ }
10
+ async market(opts = {}) {
11
+ return listSkillMarket({ ...this.ctx.base(), pageSize: 30, ...opts });
12
+ }
13
+ async get(skillId) {
14
+ return getSkill({ ...this.ctx.base(), skillId });
15
+ }
16
+ async registerContent(content, opts = {}) {
17
+ return registerSkillContent({ ...this.ctx.base(), content, ...opts });
18
+ }
19
+ async registerZip(filename, bytes, opts = {}) {
20
+ return registerSkillZip({ ...this.ctx.base(), filename, bytes, ...opts });
21
+ }
22
+ async delete(skillId) {
23
+ return deleteSkill({ ...this.ctx.base(), skillId });
24
+ }
25
+ async updateStatus(skillId, status) {
26
+ return updateSkillStatus({ ...this.ctx.base(), skillId, status });
27
+ }
28
+ async content(skillId) {
29
+ return getSkillContentIndex({ ...this.ctx.base(), skillId });
30
+ }
31
+ async fetchContent(skillId) {
32
+ return fetchSkillContent({ ...this.ctx.base(), skillId });
33
+ }
34
+ async readFile(skillId, relPath) {
35
+ return readSkillFile({ ...this.ctx.base(), skillId, relPath });
36
+ }
37
+ async fetchFile(skillId, relPath) {
38
+ return fetchSkillFile({ ...this.ctx.base(), skillId, relPath });
39
+ }
40
+ async download(skillId) {
41
+ return downloadSkill({ ...this.ctx.base(), skillId });
42
+ }
43
+ async install(skillId, directory, opts = {}) {
44
+ const archive = await this.download(skillId);
45
+ return installSkillArchive({ bytes: archive.bytes, directory, force: opts.force });
46
+ }
47
+ }
@@ -40,16 +40,21 @@ export declare class VegaResource {
40
40
  createResource(body: string): Promise<unknown>;
41
41
  updateResource(id: string, body: string): Promise<unknown>;
42
42
  deleteResources(ids: string): Promise<unknown>;
43
+ createDatasetDocs(id: string, body: string): Promise<unknown>;
44
+ updateDatasetDocs(id: string, body: string): Promise<unknown>;
45
+ deleteDatasetDocs(id: string, docIds: string): Promise<unknown>;
46
+ deleteDatasetDocsQuery(id: string, body: string): Promise<unknown>;
47
+ buildDataset(id: string, mode?: string): Promise<unknown>;
48
+ getDatasetBuildStatus(id: string, taskId: string): Promise<unknown>;
49
+ executeQuery(body: string): Promise<unknown>;
50
+ listAllResources(opts?: {
51
+ limit?: number;
52
+ offset?: number;
53
+ }): Promise<unknown[]>;
43
54
  listConnectorTypes(): Promise<unknown[]>;
44
55
  getConnectorType(type: string): Promise<unknown>;
45
56
  registerConnectorType(body: string): Promise<unknown>;
46
57
  updateConnectorType(type: string, body: string): Promise<unknown>;
47
58
  deleteConnectorType(type: string): Promise<unknown>;
48
59
  setConnectorTypeEnabled(type: string, enabled: boolean): Promise<unknown>;
49
- listDiscoverTasks(opts?: {
50
- status?: string;
51
- limit?: number;
52
- offset?: number;
53
- }): Promise<unknown[]>;
54
- getDiscoverTask(id: string): Promise<unknown>;
55
60
  }
@@ -1,4 +1,4 @@
1
- import { vegaHealth, listVegaCatalogs, getVegaCatalog, createVegaCatalog, updateVegaCatalog, deleteVegaCatalogs, vegaCatalogHealthStatus, testVegaCatalogConnection, discoverVegaCatalog, listVegaCatalogResources, listVegaResources, getVegaResource, queryVegaResourceData, createVegaResource, updateVegaResource, deleteVegaResources, listVegaConnectorTypes, getVegaConnectorType, registerVegaConnectorType, updateVegaConnectorType, deleteVegaConnectorType, setVegaConnectorTypeEnabled, listVegaDiscoverTasks, getVegaDiscoverTask, } from "../api/vega.js";
1
+ import { vegaHealth, listVegaCatalogs, getVegaCatalog, createVegaCatalog, updateVegaCatalog, deleteVegaCatalogs, vegaCatalogHealthStatus, testVegaCatalogConnection, discoverVegaCatalog, listVegaCatalogResources, listVegaResources, getVegaResource, queryVegaResourceData, createVegaResource, updateVegaResource, deleteVegaResources, createVegaDatasetDocs, updateVegaDatasetDocs, deleteVegaDatasetDocs, deleteVegaDatasetDocsQuery, buildVegaDataset, getVegaDatasetBuildStatus, executeVegaQuery, listAllVegaResources, listVegaConnectorTypes, getVegaConnectorType, registerVegaConnectorType, updateVegaConnectorType, deleteVegaConnectorType, setVegaConnectorTypeEnabled, } from "../api/vega.js";
2
2
  function unwrapArray(raw) {
3
3
  const parsed = JSON.parse(raw);
4
4
  if (Array.isArray(parsed))
@@ -83,6 +83,42 @@ export class VegaResource {
83
83
  const raw = await deleteVegaResources({ ...this.ctx.base(), ids });
84
84
  return raw ? JSON.parse(raw) : {};
85
85
  }
86
+ // ── Dataset Docs ────────────────────────────────────────────────────────────
87
+ async createDatasetDocs(id, body) {
88
+ const raw = await createVegaDatasetDocs({ ...this.ctx.base(), id, body });
89
+ return JSON.parse(raw);
90
+ }
91
+ async updateDatasetDocs(id, body) {
92
+ const raw = await updateVegaDatasetDocs({ ...this.ctx.base(), id, body });
93
+ return raw ? JSON.parse(raw) : {};
94
+ }
95
+ async deleteDatasetDocs(id, docIds) {
96
+ const raw = await deleteVegaDatasetDocs({ ...this.ctx.base(), id, docIds });
97
+ return raw ? JSON.parse(raw) : {};
98
+ }
99
+ async deleteDatasetDocsQuery(id, body) {
100
+ const raw = await deleteVegaDatasetDocsQuery({ ...this.ctx.base(), id, body });
101
+ return raw ? JSON.parse(raw) : {};
102
+ }
103
+ // ── Dataset Build ──────────────────────────────────────────────────────────
104
+ async buildDataset(id, mode) {
105
+ const raw = await buildVegaDataset({ ...this.ctx.base(), id, mode });
106
+ return JSON.parse(raw);
107
+ }
108
+ async getDatasetBuildStatus(id, taskId) {
109
+ const raw = await getVegaDatasetBuildStatus({ ...this.ctx.base(), id, taskId });
110
+ return JSON.parse(raw);
111
+ }
112
+ // ── Query ──────────────────────────────────────────────────────────────────
113
+ async executeQuery(body) {
114
+ const raw = await executeVegaQuery({ ...this.ctx.base(), body });
115
+ return JSON.parse(raw);
116
+ }
117
+ // ── Resource List All ──────────────────────────────────────────────────────
118
+ async listAllResources(opts = {}) {
119
+ const raw = await listAllVegaResources({ ...this.ctx.base(), ...opts });
120
+ return unwrapArray(raw);
121
+ }
86
122
  // ── Connector Types ─────────────────────────────────────────────────────────
87
123
  async listConnectorTypes() {
88
124
  const raw = await listVegaConnectorTypes(this.ctx.base());
@@ -108,13 +144,4 @@ export class VegaResource {
108
144
  const raw = await setVegaConnectorTypeEnabled({ ...this.ctx.base(), type, enabled });
109
145
  return raw ? JSON.parse(raw) : {};
110
146
  }
111
- // ── Discover Tasks ──────────────────────────────────────────────────────────
112
- async listDiscoverTasks(opts = {}) {
113
- const raw = await listVegaDiscoverTasks({ ...this.ctx.base(), ...opts });
114
- return unwrapArray(raw);
115
- }
116
- async getDiscoverTask(id) {
117
- const raw = await getVegaDiscoverTask({ ...this.ctx.base(), id });
118
- return JSON.parse(raw);
119
- }
120
147
  }
@@ -0,0 +1,136 @@
1
+ // ---------------------------------------------------------------------------
2
+ // Shared state
3
+ // ---------------------------------------------------------------------------
4
+ let navGeneration = 0;
5
+
6
+ // ---------------------------------------------------------------------------
7
+ // Utilities
8
+ // ---------------------------------------------------------------------------
9
+ function esc(s) {
10
+ if (s == null) return "";
11
+ return String(s).replace(/&/g, "&amp;").replace(/</g, "&lt;")
12
+ .replace(/>/g, "&gt;").replace(/"/g, "&quot;");
13
+ }
14
+
15
+ function enc(s) { return encodeURIComponent(s); }
16
+
17
+ function formatValue(v) {
18
+ if (v == null) return '<span class="null">β€”</span>';
19
+ if (typeof v === "object") return "<pre>" + esc(JSON.stringify(v, null, 2)) + "</pre>";
20
+ return esc(String(v));
21
+ }
22
+
23
+ // ---------------------------------------------------------------------------
24
+ // Cache utility
25
+ // ---------------------------------------------------------------------------
26
+ const CACHE_TTL = 5 * 60 * 1000;
27
+
28
+ function cachedFetch(cache, key, fetcher) {
29
+ const entry = cache[key];
30
+ if (entry && Date.now() - entry.ts < CACHE_TTL) return Promise.resolve(entry.data);
31
+ return fetcher().then(data => { cache[key] = { data, ts: Date.now() }; return data; });
32
+ }
33
+
34
+ // ---------------------------------------------------------------------------
35
+ // API helper
36
+ // ---------------------------------------------------------------------------
37
+ async function api(method, url, body) {
38
+ const opts = { method, headers: {} };
39
+ if (body) {
40
+ opts.headers["Content-Type"] = "application/json";
41
+ opts.body = JSON.stringify(body);
42
+ }
43
+ const res = await fetch(url, opts);
44
+ if (!res.ok) {
45
+ let msg = `${res.status} ${res.statusText}`;
46
+ try { const err = await res.json(); if (err.error) msg = err.error; } catch {}
47
+ const error = new Error(msg);
48
+ error.status = res.status;
49
+ throw error;
50
+ }
51
+ return res.json();
52
+ }
53
+
54
+ // ---------------------------------------------------------------------------
55
+ // List extraction helper (handles various API response shapes)
56
+ // ---------------------------------------------------------------------------
57
+ function extractList(obj) {
58
+ if (obj == null || obj.error) return [];
59
+ if (Array.isArray(obj)) return obj;
60
+ for (const k of ["entries", "data", "knowledge_networks", "items"]) {
61
+ if (Array.isArray(obj[k])) return obj[k];
62
+ }
63
+ return [];
64
+ }
65
+
66
+ // ---------------------------------------------------------------------------
67
+ // Router
68
+ // ---------------------------------------------------------------------------
69
+ function getRoute() {
70
+ const hash = location.hash.slice(1) || "/";
71
+ const [path, qs] = hash.split("?");
72
+ const parts = path.split("/").filter(Boolean);
73
+ const params = new URLSearchParams(qs || "");
74
+
75
+ if (parts.length === 0) return { view: "dashboard" };
76
+
77
+ const tab = parts[0];
78
+ return { tab, parts: parts.slice(1), params };
79
+ }
80
+
81
+ function navigate() {
82
+ navGeneration++;
83
+ const route = getRoute();
84
+ const $content = document.getElementById("content");
85
+
86
+ // Update active tab
87
+ document.querySelectorAll("#tab-bar .tab").forEach(t => {
88
+ const tabName = t.dataset.tab;
89
+ const isActive = route.view === "dashboard"
90
+ ? tabName === "dashboard"
91
+ : tabName === route.tab;
92
+ t.classList.toggle("active", isActive);
93
+ });
94
+
95
+ // Dispatch to tab renderer
96
+ if (route.view === "dashboard") {
97
+ if (typeof renderDashboard === "function") renderDashboard($content);
98
+ else $content.innerHTML = '<div class="loading">Dashboard loading...</div>';
99
+ } else if (route.tab === "chat") {
100
+ if (typeof renderChat === "function") renderChat($content, route.parts, route.params);
101
+ else $content.innerHTML = '<div class="loading">Chat loading...</div>';
102
+ } else if (route.tab === "bkn") {
103
+ if (typeof renderBkn === "function") renderBkn($content, route.parts, route.params);
104
+ else $content.innerHTML = '<div class="loading">BKN loading...</div>';
105
+ } else if (route.tab === "vega") {
106
+ if (typeof renderVega === "function") renderVega($content, route.parts, route.params);
107
+ else $content.innerHTML = '<div class="loading">Vega loading...</div>';
108
+ } else {
109
+ $content.innerHTML = '<div class="error-banner">Unknown route</div>';
110
+ }
111
+ }
112
+
113
+ // ---------------------------------------------------------------------------
114
+ // Init
115
+ // ---------------------------------------------------------------------------
116
+ window.addEventListener("hashchange", navigate);
117
+ window.addEventListener("DOMContentLoaded", () => {
118
+ // Theme Toggle
119
+ const themeToggle = document.getElementById("theme-toggle");
120
+ if (themeToggle) {
121
+ const savedTheme = localStorage.getItem("kweaver-theme");
122
+ if (savedTheme) {
123
+ document.documentElement.setAttribute("data-theme", savedTheme);
124
+ themeToggle.textContent = savedTheme === "dark" ? "β˜€οΈ" : "πŸŒ™";
125
+ }
126
+ themeToggle.addEventListener("click", () => {
127
+ const currentTheme = document.documentElement.getAttribute("data-theme");
128
+ const newTheme = currentTheme === "dark" ? "light" : "dark";
129
+ document.documentElement.setAttribute("data-theme", newTheme);
130
+ localStorage.setItem("kweaver-theme", newTheme);
131
+ themeToggle.textContent = newTheme === "dark" ? "β˜€οΈ" : "πŸŒ™";
132
+ });
133
+ }
134
+
135
+ navigate();
136
+ });