@xano/cli 1.0.4-beta.3 → 1.0.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.
Files changed (42) hide show
  1. package/README.md +4 -51
  2. package/dist/base-command.d.ts +0 -27
  3. package/dist/base-command.js +1 -124
  4. package/dist/commands/auth/index.d.ts +1 -45
  5. package/dist/commands/auth/index.js +29 -197
  6. package/dist/commands/{tenant/snapshot/list → knowledge/pull}/index.d.ts +4 -6
  7. package/dist/commands/knowledge/pull/index.js +86 -0
  8. package/dist/commands/knowledge/push/index.d.ts +20 -0
  9. package/dist/commands/knowledge/push/index.js +126 -0
  10. package/dist/commands/static_host/build/create/index.d.ts +1 -9
  11. package/dist/commands/static_host/build/create/index.js +4 -54
  12. package/dist/commands/static_host/build/get/index.d.ts +1 -1
  13. package/dist/commands/static_host/build/get/index.js +10 -16
  14. package/dist/utils/knowledge-sync.d.ts +108 -0
  15. package/dist/utils/knowledge-sync.js +380 -0
  16. package/dist/utils/multidoc-push.js +17 -21
  17. package/dist/utils/reference-checker.js +2 -2
  18. package/oclif.manifest.json +2951 -4086
  19. package/package.json +1 -3
  20. package/dist/commands/static_host/build/delete/index.d.ts +0 -19
  21. package/dist/commands/static_host/build/delete/index.js +0 -114
  22. package/dist/commands/static_host/build/pull/index.d.ts +0 -52
  23. package/dist/commands/static_host/build/pull/index.js +0 -300
  24. package/dist/commands/static_host/build/push/index.d.ts +0 -23
  25. package/dist/commands/static_host/build/push/index.js +0 -225
  26. package/dist/commands/static_host/create/index.d.ts +0 -17
  27. package/dist/commands/static_host/create/index.js +0 -86
  28. package/dist/commands/static_host/deploy/index.d.ts +0 -18
  29. package/dist/commands/static_host/deploy/index.js +0 -105
  30. package/dist/commands/static_host/edit/index.d.ts +0 -23
  31. package/dist/commands/static_host/edit/index.js +0 -151
  32. package/dist/commands/static_host/get/index.d.ts +0 -18
  33. package/dist/commands/static_host/get/index.js +0 -94
  34. package/dist/commands/static_host/migrate/index.d.ts +0 -44
  35. package/dist/commands/static_host/migrate/index.js +0 -205
  36. package/dist/commands/tenant/snapshot/create/index.d.ts +0 -17
  37. package/dist/commands/tenant/snapshot/create/index.js +0 -78
  38. package/dist/commands/tenant/snapshot/delete/index.d.ts +0 -19
  39. package/dist/commands/tenant/snapshot/delete/index.js +0 -102
  40. package/dist/commands/tenant/snapshot/list/index.js +0 -96
  41. package/dist/commands/tenant/snapshot/swap/index.d.ts +0 -19
  42. package/dist/commands/tenant/snapshot/swap/index.js +0 -103
@@ -0,0 +1,86 @@
1
+ import { Flags } from '@oclif/core';
2
+ import * as fs from 'node:fs';
3
+ import { dirname, resolve } from 'node:path';
4
+ import BaseCommand from '../../../base-command.js';
5
+ import { fetchKnowledgeList, safeKnowledgePath } from '../../../utils/knowledge-sync.js';
6
+ export default class KnowledgePull extends BaseCommand {
7
+ static description = 'Pull knowledge files from a workspace. Each knowledge item name is a path (e.g. "some/thing/CLAUDE.md") and its content is written to that path under the output directory.';
8
+ static examples = [
9
+ `$ xano knowledge pull
10
+ Pulled 4 knowledge files to current directory
11
+ `,
12
+ `$ xano knowledge pull -d ./knowledge
13
+ Pulled 4 knowledge files to ./knowledge
14
+ `,
15
+ `$ xano knowledge pull -d ./knowledge -w 40`,
16
+ `$ xano knowledge pull -b dev`,
17
+ ];
18
+ static flags = {
19
+ ...BaseCommand.baseFlags,
20
+ branch: Flags.string({
21
+ char: 'b',
22
+ description: 'Branch name (optional if set in profile, defaults to live)',
23
+ required: false,
24
+ }),
25
+ directory: Flags.string({
26
+ char: 'd',
27
+ default: '.',
28
+ description: 'Output directory for pulled knowledge files (defaults to current directory)',
29
+ required: false,
30
+ }),
31
+ workspace: Flags.string({
32
+ char: 'w',
33
+ description: 'Workspace ID (optional if set in profile)',
34
+ required: false,
35
+ }),
36
+ };
37
+ async run() {
38
+ const { flags } = await this.parse(KnowledgePull);
39
+ const { profile, profileName } = this.resolveProfile(flags);
40
+ // Determine workspace_id from flag or profile
41
+ let workspaceId;
42
+ if (flags.workspace) {
43
+ workspaceId = flags.workspace;
44
+ }
45
+ else if (profile.workspace) {
46
+ workspaceId = profile.workspace;
47
+ }
48
+ else {
49
+ this.error(`Workspace ID is required. Either:\n` +
50
+ ` 1. Provide it as a flag: xano knowledge pull -w <workspace_id>\n` +
51
+ ` 2. Set it in your profile using: xano profile:edit ${profileName} -w <workspace_id>`);
52
+ }
53
+ const branch = flags.branch || profile.branch || '';
54
+ let items;
55
+ try {
56
+ items = await fetchKnowledgeList({
57
+ accessToken: profile.access_token,
58
+ branch,
59
+ instanceOrigin: profile.instance_origin,
60
+ verboseFetch: this.verboseFetch.bind(this),
61
+ workspaceId,
62
+ }, flags.verbose);
63
+ }
64
+ catch (error) {
65
+ this.error(`Failed to fetch knowledge: ${error.message}`);
66
+ }
67
+ if (items.length === 0) {
68
+ this.log('No knowledge found in workspace');
69
+ return;
70
+ }
71
+ const outputDir = resolve(flags.directory);
72
+ fs.mkdirSync(outputDir, { recursive: true });
73
+ let writtenCount = 0;
74
+ for (const item of items) {
75
+ const filePath = safeKnowledgePath(outputDir, item.name);
76
+ if (!filePath) {
77
+ this.warn(`Skipping knowledge "${item.name}": name is not a safe relative path`);
78
+ continue;
79
+ }
80
+ fs.mkdirSync(dirname(filePath), { recursive: true });
81
+ fs.writeFileSync(filePath, item.content ?? '', 'utf8');
82
+ writtenCount++;
83
+ }
84
+ this.log(`Pulled ${writtenCount} knowledge files to ${flags.directory}`);
85
+ }
86
+ }
@@ -0,0 +1,20 @@
1
+ import BaseCommand from '../../../base-command.js';
2
+ export default class KnowledgePush extends BaseCommand {
3
+ static description: string;
4
+ static examples: string[];
5
+ static flags: {
6
+ branch: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
+ delete: import("@oclif/core/interfaces").BooleanFlag<boolean>;
8
+ directory: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
9
+ 'dry-run': import("@oclif/core/interfaces").BooleanFlag<boolean>;
10
+ exclude: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
11
+ force: import("@oclif/core/interfaces").BooleanFlag<boolean>;
12
+ include: import("@oclif/core/interfaces").OptionFlag<string[] | undefined, import("@oclif/core/interfaces").CustomOptions>;
13
+ sync: import("@oclif/core/interfaces").BooleanFlag<boolean>;
14
+ workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
15
+ config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
16
+ profile: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
17
+ verbose: import("@oclif/core/interfaces").BooleanFlag<boolean>;
18
+ };
19
+ run(): Promise<void>;
20
+ }
@@ -0,0 +1,126 @@
1
+ import { Flags } from '@oclif/core';
2
+ import * as fs from 'node:fs';
3
+ import { resolve } from 'node:path';
4
+ import BaseCommand from '../../../base-command.js';
5
+ import { executeKnowledgePush } from '../../../utils/knowledge-sync.js';
6
+ export default class KnowledgePush extends BaseCommand {
7
+ static description = '[IMPORTANT] ALWAYS run --dry-run first and show the user the output before pushing. Push local knowledge files to a workspace. Each file becomes a knowledge item named by its relative path (e.g. "some/thing/CLAUDE.md"). By default, only changed files are pushed (partial mode). Use --sync to compare all files (required for --delete). Shows a preview of changes before pushing unless --force is specified. Use --dry-run to preview only.';
8
+ static examples = [
9
+ `$ xano knowledge push
10
+ Push from current directory (default partial mode)
11
+ `,
12
+ `$ xano knowledge push -d ./knowledge
13
+ Push from a specific directory
14
+ `,
15
+ `$ xano knowledge push --dry-run
16
+ Preview changes without pushing
17
+ `,
18
+ `$ xano knowledge push --sync --delete
19
+ Push all files and delete remote knowledge not included
20
+ `,
21
+ `$ xano knowledge push --force
22
+ Skip preview and push immediately (for CI/CD)
23
+ `,
24
+ `$ xano knowledge push -i "guides/*"
25
+ Push only files matching the glob pattern
26
+ `,
27
+ `$ xano knowledge push -e "**/README.md"
28
+ Push all files except READMEs
29
+ `,
30
+ ];
31
+ static flags = {
32
+ ...BaseCommand.baseFlags,
33
+ branch: Flags.string({
34
+ char: 'b',
35
+ description: 'Branch name (optional if set in profile, defaults to live)',
36
+ required: false,
37
+ }),
38
+ delete: Flags.boolean({
39
+ default: false,
40
+ description: '[CRITICAL] STOP and confirm with the user before running. Delete remote knowledge not included in the push (requires --sync).',
41
+ required: false,
42
+ }),
43
+ directory: Flags.string({
44
+ char: 'd',
45
+ default: '.',
46
+ description: 'Directory containing knowledge files to push (defaults to current directory)',
47
+ required: false,
48
+ }),
49
+ 'dry-run': Flags.boolean({
50
+ default: false,
51
+ description: 'Show preview of changes without pushing (exit after preview)',
52
+ required: false,
53
+ }),
54
+ exclude: Flags.string({
55
+ char: 'e',
56
+ description: 'Glob pattern to exclude files (e.g. "**/README.md"). Matched against relative paths from the push directory.',
57
+ multiple: true,
58
+ required: false,
59
+ }),
60
+ force: Flags.boolean({
61
+ default: false,
62
+ description: '[CRITICAL] NEVER run without explicit user confirmation. Skips preview and confirmation prompt (for CI/CD pipelines).',
63
+ required: false,
64
+ }),
65
+ include: Flags.string({
66
+ char: 'i',
67
+ description: 'Glob pattern to include files (e.g. "guides/*"). Matched against relative paths from the push directory.',
68
+ multiple: true,
69
+ required: false,
70
+ }),
71
+ sync: Flags.boolean({
72
+ default: false,
73
+ description: 'Full push — compare all files, not just changed ones. Required for --delete.',
74
+ required: false,
75
+ }),
76
+ workspace: Flags.string({
77
+ char: 'w',
78
+ description: 'Workspace ID (optional if set in profile)',
79
+ required: false,
80
+ }),
81
+ };
82
+ async run() {
83
+ const { flags } = await this.parse(KnowledgePush);
84
+ const { profile, profileName } = this.resolveProfile(flags);
85
+ // Determine workspace_id from flag or profile
86
+ let workspaceId;
87
+ if (flags.workspace) {
88
+ workspaceId = flags.workspace;
89
+ }
90
+ else if (profile.workspace) {
91
+ workspaceId = profile.workspace;
92
+ }
93
+ else {
94
+ this.error(`Workspace ID is required. Either:\n` +
95
+ ` 1. Provide it as a flag: xano knowledge push -w <workspace_id>\n` +
96
+ ` 2. Set it in your profile using: xano profile:edit ${profileName} -w <workspace_id>`);
97
+ }
98
+ const inputDir = resolve(flags.directory);
99
+ if (!fs.existsSync(inputDir)) {
100
+ this.error(`Directory not found: ${inputDir}`);
101
+ }
102
+ if (!fs.statSync(inputDir).isDirectory()) {
103
+ this.error(`Not a directory: ${inputDir}`);
104
+ }
105
+ const branch = flags.branch || profile.branch || '';
106
+ const pushFlags = {
107
+ delete: flags.delete,
108
+ 'dry-run': flags['dry-run'],
109
+ exclude: flags.exclude,
110
+ force: flags.force,
111
+ include: flags.include,
112
+ sync: flags.sync,
113
+ verbose: flags.verbose,
114
+ };
115
+ await executeKnowledgePush({
116
+ accessToken: profile.access_token,
117
+ branch,
118
+ cliVersion: this.config.version,
119
+ command: this,
120
+ inputDir,
121
+ instanceOrigin: profile.instance_origin,
122
+ verboseFetch: this.verboseFetch.bind(this),
123
+ workspaceId,
124
+ }, pushFlags);
125
+ }
126
+ }
@@ -1,12 +1,5 @@
1
1
  import BaseCommand from '../../../../base-command.js';
2
- /**
3
- * Generate a default build name from a compact timestamp: `YYYYMMDD-HHmmss`
4
- * (e.g. `20260531-143022`). Sortable, distinct down to the second, and uses
5
- * local time so it lines up with when the user ran the command.
6
- */
7
- export declare function generateBuildName(date?: Date): string;
8
2
  export default class StaticHostBuildCreate extends BaseCommand {
9
- static hidden: boolean;
10
3
  static args: {
11
4
  static_host: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
12
5
  };
@@ -15,8 +8,7 @@ export default class StaticHostBuildCreate extends BaseCommand {
15
8
  static flags: {
16
9
  description: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
17
10
  file: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
18
- name: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
19
- 'no-wait': import("@oclif/core/interfaces").BooleanFlag<boolean>;
11
+ name: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
20
12
  output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
21
13
  workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
22
14
  config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -2,42 +2,20 @@ import { Args, Flags } from '@oclif/core';
2
2
  import * as fs from 'node:fs';
3
3
  import * as path from 'node:path';
4
4
  import BaseCommand from '../../../../base-command.js';
5
- const pad2 = (n) => String(n).padStart(2, '0');
6
- /**
7
- * Generate a default build name from a compact timestamp: `YYYYMMDD-HHmmss`
8
- * (e.g. `20260531-143022`). Sortable, distinct down to the second, and uses
9
- * local time so it lines up with when the user ran the command.
10
- */
11
- export function generateBuildName(date = new Date()) {
12
- const y = date.getFullYear();
13
- const mo = pad2(date.getMonth() + 1);
14
- const d = pad2(date.getDate());
15
- const h = pad2(date.getHours());
16
- const mi = pad2(date.getMinutes());
17
- const s = pad2(date.getSeconds());
18
- return `${y}${mo}${d}-${h}${mi}${s}`;
19
- }
20
5
  export default class StaticHostBuildCreate extends BaseCommand {
21
- static hidden = true;
22
6
  static args = {
23
7
  static_host: Args.string({
24
8
  description: 'Static Host name',
25
9
  required: true,
26
10
  }),
27
11
  };
28
- static description = '[Deprecated: use "static_host build push -f <file>" instead] Create a new build from a zip file';
12
+ static description = 'Create a new build for a static host';
29
13
  static examples = [
30
14
  `$ xano static_host:build:create default -f ./build.zip -n "v1.0.0"
31
15
  Build created successfully!
32
16
  ID: 123
33
17
  Name: v1.0.0
34
18
  Status: pending
35
- `,
36
- `$ xano static_host:build:create default -f ./build.zip
37
- Build created successfully!
38
- ID: 123
39
- Name: 20260531-143022
40
- Status: pending
41
19
  `,
42
20
  `$ xano static_host:build:create default -w 40 -f ./dist.zip -n "production" -d "Production build"
43
21
  Build created successfully!
@@ -67,13 +45,8 @@ Description: Production build
67
45
  }),
68
46
  name: Flags.string({
69
47
  char: 'n',
70
- description: 'Build name (auto-generated from the current timestamp if omitted)',
71
- required: false,
72
- }),
73
- 'no-wait': Flags.boolean({
74
- default: false,
75
- description: 'Return immediately after upload instead of waiting for the build to finish',
76
- required: false,
48
+ description: 'Build name',
49
+ required: true,
77
50
  }),
78
51
  output: Flags.string({
79
52
  char: 'o',
@@ -89,7 +62,6 @@ Description: Production build
89
62
  }),
90
63
  };
91
64
  async run() {
92
- this.warn('`static_host build create` is deprecated. Use `static_host build push -f <file>` instead.');
93
65
  const { args, flags } = await this.parse(StaticHostBuildCreate);
94
66
  const { profile, profileName } = this.resolveProfile(flags);
95
67
  // Determine workspace_id from flag or profile
@@ -130,10 +102,7 @@ Description: Production build
130
102
  const fileBuffer = fs.readFileSync(filePath);
131
103
  const blob = new Blob([fileBuffer], { type: 'application/zip' });
132
104
  formData.append('file', blob, path.basename(filePath));
133
- // Name is optional — fall back to a timestamped name so builds can be
134
- // created without thinking up a label each time.
135
- const buildName = flags.name ?? generateBuildName();
136
- formData.append('name', buildName);
105
+ formData.append('name', flags.name);
137
106
  if (flags.description) {
138
107
  formData.append('description', flags.description);
139
108
  }
@@ -172,25 +141,6 @@ Description: Production build
172
141
  this.log(`Description: ${flags.description}`);
173
142
  }
174
143
  }
175
- // Async (package.json) builds keep running after upload. Unless --no-wait,
176
- // poll until the build finishes so the CLI mirrors the UI's progress.
177
- const inProgress = result.status !== undefined && !['error', 'ok'].includes(result.status);
178
- if (inProgress && !flags['no-wait']) {
179
- const finalStatus = await this.waitForBuild({
180
- buildId: result.id,
181
- profile,
182
- quiet: flags.output === 'json',
183
- staticHost: args.static_host,
184
- verbose: flags.verbose,
185
- workspaceId,
186
- });
187
- if (finalStatus === 'error') {
188
- this.error(`Build ${result.id} failed (status: error). Check the build log with: xano static_host build get ${args.static_host} --build_id ${result.id}`);
189
- }
190
- }
191
- if (flags.output !== 'json') {
192
- await this.logStaticHostUrls({ profile, staticHost: args.static_host, verbose: flags.verbose, workspaceId });
193
- }
194
144
  }
195
145
  catch (error) {
196
146
  if (error instanceof Error) {
@@ -1,12 +1,12 @@
1
1
  import BaseCommand from '../../../../base-command.js';
2
2
  export default class StaticHostBuildGet extends BaseCommand {
3
3
  static args: {
4
+ build_id: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
4
5
  static_host: import("@oclif/core/interfaces").Arg<string, Record<string, unknown>>;
5
6
  };
6
7
  static description: string;
7
8
  static examples: string[];
8
9
  static flags: {
9
- build_id: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
10
10
  output: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
11
11
  workspace: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
12
12
  config: import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
@@ -2,6 +2,10 @@ import { Args, Flags } from '@oclif/core';
2
2
  import BaseCommand from '../../../../base-command.js';
3
3
  export default class StaticHostBuildGet extends BaseCommand {
4
4
  static args = {
5
+ build_id: Args.string({
6
+ description: 'Build ID',
7
+ required: true,
8
+ }),
5
9
  static_host: Args.string({
6
10
  description: 'Static Host name',
7
11
  required: true,
@@ -9,24 +13,24 @@ export default class StaticHostBuildGet extends BaseCommand {
9
13
  };
10
14
  static description = 'Get details of a specific build for a static host';
11
15
  static examples = [
12
- `$ xano static_host:build:get default --build_id 52
16
+ `$ xano static_host:build:get default 52
13
17
  Build Details:
14
18
  ID: 52
15
19
  Name: v1.0.0
16
20
  Status: completed
17
21
  `,
18
- `$ xano static_host:build:get default --build_id 52 -w 40
22
+ `$ xano static_host:build:get default 52 -w 40
19
23
  Build Details:
20
24
  ID: 52
21
25
  Name: v1.0.0
22
26
  Status: completed
23
27
  `,
24
- `$ xano static_host:build:get myhost --build_id 123 --profile production
28
+ `$ xano static_host:build:get myhost 123 --profile production
25
29
  Build Details:
26
30
  ID: 123
27
31
  Name: production-build
28
32
  `,
29
- `$ xano static_host:build:get default --build_id 52 -o json
33
+ `$ xano static_host:build:get default 52 -o json
30
34
  {
31
35
  "id": 52,
32
36
  "name": "v1.0.0",
@@ -36,10 +40,6 @@ Name: production-build
36
40
  ];
37
41
  static flags = {
38
42
  ...BaseCommand.baseFlags,
39
- build_id: Flags.string({
40
- description: 'Build ID',
41
- required: true,
42
- }),
43
43
  output: Flags.string({
44
44
  char: 'o',
45
45
  default: 'summary',
@@ -66,11 +66,11 @@ Name: production-build
66
66
  }
67
67
  else {
68
68
  this.error(`Workspace ID is required. Either:\n` +
69
- ` 1. Provide it as a flag: xano static_host:build:get <static_host> --build_id <id> -w <workspace_id>\n` +
69
+ ` 1. Provide it as a flag: xano static_host:build:get <static_host> <build_id> -w <workspace_id>\n` +
70
70
  ` 2. Set it in your profile using: xano profile:edit ${profileName} -w <workspace_id>`);
71
71
  }
72
72
  // Construct the API URL
73
- const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/static_host/${args.static_host}/build/${flags.build_id}`;
73
+ const apiUrl = `${profile.instance_origin}/api:meta/workspace/${workspaceId}/static_host/${args.static_host}/build/${args.build_id}`;
74
74
  // Fetch build from the API
75
75
  try {
76
76
  const response = await this.verboseFetch(apiUrl, {
@@ -104,12 +104,6 @@ Name: production-build
104
104
  if (build.status) {
105
105
  this.log(`Status: ${build.status}`);
106
106
  }
107
- if (typeof build.file_count === 'number') {
108
- this.log(`Files: ${build.file_count}`);
109
- }
110
- if (typeof build.file_bytes === 'number') {
111
- this.log(`Size: ${build.file_bytes} bytes`);
112
- }
113
107
  if (build.created_at) {
114
108
  this.log(`Created: ${build.created_at}`);
115
109
  }
@@ -0,0 +1,108 @@
1
+ import { Command } from '@oclif/core';
2
+ /** A knowledge record as returned by the Metadata API list endpoint. */
3
+ export interface KnowledgeItem {
4
+ branch?: {
5
+ id: number;
6
+ };
7
+ content?: string;
8
+ description?: string;
9
+ enabled?: boolean;
10
+ id: number;
11
+ knowledge_type?: string;
12
+ mode?: string;
13
+ name: string;
14
+ references?: string[];
15
+ scope?: string;
16
+ tag?: string[];
17
+ }
18
+ /** A local knowledge file: its API name (relative path) and content. */
19
+ export interface LocalKnowledgeEntry {
20
+ content: string;
21
+ filePath: string;
22
+ name: string;
23
+ }
24
+ export interface KnowledgePlan {
25
+ creates: LocalKnowledgeEntry[];
26
+ deletes: KnowledgeItem[];
27
+ unchanged: Array<{
28
+ entry: LocalKnowledgeEntry;
29
+ remote: KnowledgeItem;
30
+ }>;
31
+ updates: Array<{
32
+ entry: LocalKnowledgeEntry;
33
+ remote: KnowledgeItem;
34
+ }>;
35
+ }
36
+ export interface KnowledgePushFlags {
37
+ delete: boolean;
38
+ 'dry-run': boolean;
39
+ exclude?: string[];
40
+ force: boolean;
41
+ include?: string[];
42
+ sync: boolean;
43
+ verbose: boolean;
44
+ }
45
+ export interface KnowledgeApiContext {
46
+ accessToken: string;
47
+ /** Branch name ('' = live branch) */
48
+ branch: string;
49
+ instanceOrigin: string;
50
+ verboseFetch: (url: string, options: RequestInit, verbose: boolean, authToken?: string) => Promise<Response>;
51
+ workspaceId: string;
52
+ }
53
+ export interface KnowledgePushContext extends KnowledgeApiContext {
54
+ cliVersion: string;
55
+ command: Command;
56
+ inputDir: string;
57
+ }
58
+ export declare const MAX_NAME_LENGTH = 200;
59
+ /**
60
+ * Validate a knowledge name (a relative path like "some/thing/CLAUDE.md")
61
+ * against the Metadata API's accepted character set and length.
62
+ * Returns null when valid, otherwise a human-readable reason.
63
+ */
64
+ export declare function validateKnowledgeName(name: string): null | string;
65
+ /**
66
+ * Resolve a knowledge name to a local file path inside baseDir, rejecting
67
+ * names that would escape it (absolute paths, "..", etc.).
68
+ * Returns null when the name is unsafe.
69
+ */
70
+ export declare function safeKnowledgePath(baseDir: string, name: null | string | undefined): null | string;
71
+ /**
72
+ * Infer the knowledge_type for a newly created knowledge item from its
73
+ * filename. AGENTS.md and SKILL.md are special-cased; everything else is a doc.
74
+ */
75
+ export declare function inferKnowledgeType(name: string): string;
76
+ /**
77
+ * Recursively collect all files under a directory, skipping hidden files,
78
+ * hidden directories, and node_modules. Sorted for deterministic ordering.
79
+ */
80
+ export declare function collectKnowledgeFiles(dir: string): string[];
81
+ /**
82
+ * Read local files into knowledge entries. The knowledge name is the path
83
+ * relative to inputDir, using forward slashes.
84
+ */
85
+ export declare function readKnowledgeEntries(files: string[], inputDir: string): LocalKnowledgeEntry[];
86
+ /**
87
+ * Compute the create/update/delete plan by matching local entries against
88
+ * remote knowledge items by name.
89
+ */
90
+ export declare function buildKnowledgePlan(localEntries: LocalKnowledgeEntry[], remoteItems: KnowledgeItem[]): KnowledgePlan;
91
+ export declare function renderKnowledgePreview(plan: KnowledgePlan, opts: {
92
+ cliVersion: string;
93
+ instanceOrigin: string;
94
+ label: string;
95
+ partial: boolean;
96
+ willDelete: boolean;
97
+ }, log: (msg: string) => void): void;
98
+ /**
99
+ * Fetch all knowledge items (with content) for a workspace/branch.
100
+ */
101
+ export declare function fetchKnowledgeList(ctx: KnowledgeApiContext, verbose: boolean): Promise<KnowledgeItem[]>;
102
+ /**
103
+ * Execute a knowledge push: collect local files, diff against remote by name,
104
+ * preview, confirm, then apply creates/updates/deletes through the Metadata API.
105
+ * Mirrors the UX of `workspace push` (partial by default, --sync for full,
106
+ * --delete to remove remote-only items, --dry-run / --force).
107
+ */
108
+ export declare function executeKnowledgePush(ctx: KnowledgePushContext, flags: KnowledgePushFlags): Promise<void>;