@native-knowledge/cli 0.1.0-rc.2 → 0.1.0-rc.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/dist/agent-entry-cli.js +2 -0
- package/dist/cli.js +9 -4
- package/dist/commands.js +26 -0
- package/dist/errors.js +2 -2
- package/dist/internal/contracts/index.js +1 -0
- package/dist/internal/contracts/resource-transfer.js +11 -0
- package/dist/internal/contracts/runtime-compatibility.js +5 -5
- package/dist/internal/serving-contracts/index.js +1 -0
- package/dist/internal/serving-contracts/mcp.js +1 -4
- package/dist/internal/serving-contracts/tenant-events.js +57 -0
- package/dist/internal/serving-contracts/tenant-management.js +1 -1
- package/package.json +3 -9
- package/README.md +0 -35
package/dist/agent-entry-cli.js
CHANGED
|
@@ -44,6 +44,8 @@ export async function runAgentEntryCommand(command, flags, client) {
|
|
|
44
44
|
if (flags.has('allow-insecure-http') && one('allow-insecure-http') !== 'true')
|
|
45
45
|
throw new Error('AGENT_CLI_INPUT_INVALID');
|
|
46
46
|
const tool = one('tool'), json = one('input-json'), file = one('input-file'), goal = one('goal'), guided = one('guided');
|
|
47
|
+
if (json !== undefined && Buffer.byteLength(json) > 131072)
|
|
48
|
+
throw new Error('AGENT_CLI_INPUT_BUDGET');
|
|
47
49
|
if (guided !== undefined && (guided !== 'true' || command !== 'agent call') || goal !== undefined && command !== 'agent task')
|
|
48
50
|
throw new Error('AGENT_CLI_INPUT_INVALID');
|
|
49
51
|
if (command === 'agent task' || command === 'agent input') {
|
package/dist/cli.js
CHANGED
|
@@ -6,18 +6,23 @@ import path from 'node:path';
|
|
|
6
6
|
import { KnowledgeAuthClient, KnowledgeTenantClient, KnowledgeAgentClient, AuthError } from '@native-knowledge/knowledge-sdk';
|
|
7
7
|
import { ProfileStore } from './profile-store.js';
|
|
8
8
|
import { login, logout, profileProvider, expectedSession } from './auth-commands.js';
|
|
9
|
-
import { commands, retired,
|
|
9
|
+
import { commands, retired, localCommands, commandHelp } from './commands.js';
|
|
10
10
|
import { parse, one, integer, smallFile, argumentsFor } from './input.js';
|
|
11
11
|
import { download } from './download.js';
|
|
12
12
|
let context, human = false;
|
|
13
13
|
async function main() {
|
|
14
14
|
const { command, flags: f } = parse(process.argv.slice(2));
|
|
15
15
|
human = f.has('human');
|
|
16
|
-
if (!command || command === 'help' || f.has('help'))
|
|
17
|
-
|
|
16
|
+
if (!command || command === 'help' || command.startsWith('help ') || f.has('help')) {
|
|
17
|
+
const topic = command === 'help' ? '' : command.startsWith('help ') ? command.slice(5) : command;
|
|
18
|
+
const value = commandHelp(topic);
|
|
19
|
+
if (!value)
|
|
20
|
+
throw new AuthError('CLI_TOOL_UNSUPPORTED');
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
18
23
|
if (retired.has(command))
|
|
19
24
|
throw new AuthError('CLI_LOCAL_ACCESS_REMOVED');
|
|
20
|
-
if (!Object.hasOwn(commands, command) && !
|
|
25
|
+
if (!Object.hasOwn(commands, command) && !localCommands.includes(command))
|
|
21
26
|
throw new AuthError('CLI_TOOL_UNSUPPORTED');
|
|
22
27
|
const store = new ProfileStore(path.resolve(one(f, 'config-dir') ?? path.join(process.env.XDG_CONFIG_HOME ?? path.join(homedir(), '.config'), 'native-knowledge'))), profileName = one(f, 'profile');
|
|
23
28
|
if (command === 'profile list') {
|
package/dist/commands.js
CHANGED
|
@@ -4,6 +4,8 @@ export const commands = {
|
|
|
4
4
|
'source list': 'tenant_source_list', 'source get': 'tenant_source_get', 'source define': 'tenant_source_define', 'source configure': 'tenant_source_configure',
|
|
5
5
|
'collection request': 'tenant_collection_request', 'collection status': 'tenant_collection_status',
|
|
6
6
|
'project list': 'tenant_project_list', 'project get': 'tenant_project_get', 'project materials': 'tenant_project_materials', 'project scope-set': 'tenant_project_scope_set', 'project lifecycle-set': 'tenant_project_lifecycle_set',
|
|
7
|
+
'event materials': 'tenant_event_materials',
|
|
8
|
+
'event connection': 'tenant_event_exchange_get', 'event status': 'tenant_event_connection_status', 'event connections': 'tenant_event_exchange_list', 'event configure': 'tenant_event_exchange_configure', 'event receipt': 'tenant_event_exchange_receipt', 'event deliveries': 'tenant_event_outbox_list', 'event recover': 'tenant_event_outbox_recover', 'event recovery-receipt': 'tenant_event_outbox_recovery_receipt', 'event gap-recover': 'tenant_event_gap_recover', 'event gap-receipt': 'tenant_event_gap_recovery_receipt', 'event baseline': 'tenant_event_gap_baseline_read',
|
|
7
9
|
'runtime status': 'tenant_runtime_status', 'work queue': 'tenant_work_queue',
|
|
8
10
|
'artifact draft': 'tenant_artifact_draft', 'artifact review': 'tenant_knowledge_review', 'artifact promote': 'tenant_artifact_promote', 'knowledge compose': 'tenant_knowledge_compose', 'insight compose': 'tenant_knowledge_compose', 'knowledge read': 'tenant_knowledge_read',
|
|
9
11
|
'material share': 'tenant_material_share', 'material revoke': 'tenant_material_revoke', 'material routes': 'tenant_material_routes', 'snapshot declare': 'tenant_snapshot_declare', 'snapshot status': 'tenant_snapshot_status',
|
|
@@ -15,3 +17,27 @@ for (const op of ['preview', 'submit', 'status', 'results', 'cycles', 'read', 'p
|
|
|
15
17
|
export const localFlags = new Set(['data-root', 'identity-database', 'node-id', 'tenant', 'user', 'agent', 'cursor-secret-env', 'file-roots', 'browser-fallback', 'projection-mode', 'consumer-profile-file']);
|
|
16
18
|
export const retired = new Set(['project-intent put', 'project-intent get', 'source put', 'source preview', 'source add-url', 'source add-file', 'source add-executor', 'source reproject', 'source drift', 'source rebind', 'source due', 'batch create', 'batch create-due', 'batch get', 'batch collector-view', 'batch run', 'batch run-get', 'material page', 'material describe', 'material scope get', 'material scope set', 'material status', 'material publish', 'material location select', 'material put', 'artifact create', 'artifact get', 'artifact list', 'artifact index', 'artifact support', 'reference gap-audit', 'delivery content-factory project', 'delivery content-factory stage', 'delivery content-factory outbox-list', 'delivery content-factory record']);
|
|
17
19
|
export const help = { name: 'native-knowledge', alias: 'knowledge-v2', schemaVersion: 1, transport: 'REMOTE_OAUTH_TENANT', commands: ['auth login|status|whoami|logout', 'profile list|use|remove', 'discover', 'tool list|describe|call', 'resource file', 'agent find', 'agent tool', 'agent call', 'agent task', 'agent input', ...Object.keys(commands)], input: '--input-file <JSON> | --input-json <JSON>; --content-file <file> for submit/draft', connection: '--server <API-root> --profile <name> --token-file <file> --tenant-id <expected-Tenant>', login: 'auth login --server <API-root> --client-id <registered-native-client> [--scope <scope> ...] [--authority-version 1|2] [--no-browser] [--callback-port <port>]', rules: ['Tenant identity comes from the server session. Project is an explicit narrowing.', 'No database, local collection or Host maintenance access.', 'Noninteractive business calls never open a browser. stdout is one JSON result.'] };
|
|
20
|
+
/** Local command names also drive offline help; live schemas remain server-owned. */
|
|
21
|
+
export const localCommands = [
|
|
22
|
+
'auth login', 'auth status', 'auth whoami', 'auth logout', 'profile list', 'profile use', 'profile remove',
|
|
23
|
+
'discover', 'tool list', 'tool describe', 'tool call', 'resource file',
|
|
24
|
+
'agent find', 'agent tool', 'agent call', 'agent task', 'agent input',
|
|
25
|
+
];
|
|
26
|
+
export const commandNames = [...localCommands, ...Object.keys(commands)];
|
|
27
|
+
export function commandHelp(topic = '') {
|
|
28
|
+
const groups = [...new Set(commandNames.filter(name => name.includes(' ')).map(name => name.split(' ')[0]))];
|
|
29
|
+
if (!topic)
|
|
30
|
+
return { ...help, groups, help: 'native-knowledge help [<group> [<command>]]' };
|
|
31
|
+
const selected = commandNames.filter(name => name === topic || name.startsWith(topic + ' '));
|
|
32
|
+
if (!selected.length)
|
|
33
|
+
return undefined;
|
|
34
|
+
return {
|
|
35
|
+
name: help.name, alias: help.alias, schemaVersion: help.schemaVersion, transport: help.transport,
|
|
36
|
+
topic, commands: selected, input: help.input, connection: help.connection, rules: help.rules,
|
|
37
|
+
...(topic === 'auth' || topic === 'auth login' ? { login: help.login } : {}),
|
|
38
|
+
...(commands[topic] && topic !== 'agent status' ? {
|
|
39
|
+
tool: commands[topic], schema: `native-knowledge tool describe --tool ${commands[topic]}`,
|
|
40
|
+
} : {}),
|
|
41
|
+
help: 'Use a command with --help; authenticated tool describe returns the current schema and availability.',
|
|
42
|
+
};
|
|
43
|
+
}
|
package/dist/errors.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { AuthError, TenantManagementSdkError, ResourceSdkError, TenantOperationUnknownError } from '@native-knowledge/knowledge-sdk';
|
|
1
|
+
import { AuthError, TenantManagementSdkError, ResourceSdkError, TenantOperationUnknownError, TenantEventOperationUnknownError } from '@native-knowledge/knowledge-sdk';
|
|
2
2
|
import { agentEntryFailure } from './agent-entry-cli.js';
|
|
3
3
|
/** A CLI failure never authorizes replay; retained phases remain partial completion. */
|
|
4
4
|
export function cliFailure(e) {
|
|
5
5
|
const status = e instanceof AuthError || e instanceof TenantManagementSdkError || e instanceof ResourceSdkError ? e.status : 0, raw = e instanceof AuthError ? e.code : e instanceof TenantManagementSdkError || e instanceof ResourceSdkError ? e.code : e instanceof Error && e.name === 'ZodError' ? 'CLI_INPUT_INVALID' : e instanceof Error && /^[A-Z][A-Z0-9_]{1,100}$/.test(e.message) ? e.message : 'CLI_OPERATION_FAILED', code = /^[A-Z][A-Z0-9_]{1,100}$/.test(raw) ? raw : 'CLI_OPERATION_FAILED', exit = (e instanceof TenantManagementSdkError || e instanceof TenantOperationUnknownError) && e.completedPhase ? 7 : code.includes('UNKNOWN') || code.includes('INCOMPLETE') ? 7 : status === 403 || code.includes('FORBIDDEN') ? 4 : status === 409 || code.includes('CONFLICT') ? 5 : status >= 500 || code.includes('TRANSPORT') ? 6 : code.includes('AUTH_') ? 3 : 2;
|
|
6
|
-
return { exit, error: { code, status, ...(agentEntryFailure(e) ?? {}), retryable: false, nextActions: code === 'AUTH_LOGOUT_REQUIRED' ? [{ command: 'native-knowledge auth logout', automatic: false }] : code === 'AUTH_CREDENTIAL_SOURCE_CONFLICT' ? [{ command: 'native-knowledge help', automatic: false }] : e instanceof TenantOperationUnknownError && e.requestId ? [{ tool: 'tenant_operation_status', arguments: { requestId: e.requestId }, automatic: false, requiredScopes: ['knowledge.workflow.read'] }] : exit === 3 ? [{ command: 'native-knowledge auth login', automatic: false }] : code === 'CLI_LOCAL_ACCESS_REMOVED' ? [{ command: 'native-knowledge help', automatic: false, documentation: 'docs/operations/tenant-cli-migration.md' }] : [], ...((e instanceof TenantManagementSdkError || e instanceof TenantOperationUnknownError) ? { completedPhase: e.completedPhase, ref: e.ref } : {}), ...(e instanceof TenantOperationUnknownError ? { requestId: e.requestId } : {}) } };
|
|
6
|
+
return { exit, error: { code, status, ...(agentEntryFailure(e) ?? {}), retryable: false, nextActions: code === 'AUTH_LOGOUT_REQUIRED' ? [{ command: 'native-knowledge auth logout', automatic: false }] : code === 'AUTH_CREDENTIAL_SOURCE_CONFLICT' ? [{ command: 'native-knowledge help', automatic: false }] : e instanceof TenantEventOperationUnknownError ? [{ tool: e.receiptTool, arguments: { requestId: e.requestId }, automatic: false, requiredScopes: ['knowledge.material.route'] }] : e instanceof TenantOperationUnknownError && e.requestId ? [{ tool: 'tenant_operation_status', arguments: { requestId: e.requestId }, automatic: false, requiredScopes: ['knowledge.workflow.read'] }] : exit === 3 ? [{ command: 'native-knowledge auth login', automatic: false }] : code === 'CLI_LOCAL_ACCESS_REMOVED' ? [{ command: 'native-knowledge help', automatic: false, documentation: 'docs/operations/tenant-cli-migration.md' }] : [], ...((e instanceof TenantManagementSdkError || e instanceof TenantOperationUnknownError) ? { completedPhase: e.completedPhase, ref: e.ref } : {}), ...((e instanceof TenantOperationUnknownError || e instanceof TenantEventOperationUnknownError) ? { requestId: e.requestId } : {}) } };
|
|
7
7
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Explicit transfer binding leaves historical Provider16 JSON and clients unchanged. */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { sha256Schema } from './common.js';
|
|
4
|
+
import { materialContextSchema } from './material-context.js';
|
|
5
|
+
import { materialAuthorityPolicySchema } from './resource-scope.js';
|
|
6
|
+
import { resourceEnvelopeSchema } from './tenant-resource-api.js';
|
|
7
|
+
export const resourceTransferRequestHeader = 'x-knowledge-resource-transfer';
|
|
8
|
+
export const resourceTransferFeature = 'context-v1';
|
|
9
|
+
export const resourceTransferResponseHeader = 'x-knowledge-resource-context';
|
|
10
|
+
export const resourceTransferBindingSchema = z.object({ schemaVersion: z.literal(1), context: materialContextSchema, policy: materialAuthorityPolicySchema, refHash: sha256Schema }).strict().superRefine((value, ctx) => { if (!resourceEnvelopeSchema.safeParse({ schemaVersion: 2, context: value.context, policy: value.policy, data: null }).success)
|
|
11
|
+
ctx.addIssue({ code: 'custom', message: 'Transfer context and policy mismatch' }); });
|
|
@@ -6,8 +6,8 @@ export const tenantCoreReadCapabilities = [
|
|
|
6
6
|
];
|
|
7
7
|
export const tenantCoreWriteCapabilities = ['TENANT_COLLECTION_V2', 'TENANT_ADMISSION_STOP_V1', 'TENANT_ADMISSION_V2'];
|
|
8
8
|
export function runtimeCompatibility(component) {
|
|
9
|
-
return { schemaVersion: 1, component, identityReadMinimum: 11, identityReadMaximum:
|
|
10
|
-
capabilities: component === 'core' ? [...tenantCoreReadCapabilities, ...tenantCoreWriteCapabilities, 'TENANT_NATIVE_CLIENT_AUTH_V1'] : [...tenantCoreReadCapabilities, 'TENANT_NATIVE_CLIENT_AUTH_V1'],
|
|
9
|
+
return { schemaVersion: 1, component, identityReadMinimum: 11, identityReadMaximum: 24,
|
|
10
|
+
capabilities: component === 'core' ? [...tenantCoreReadCapabilities, ...tenantCoreWriteCapabilities, 'TENANT_NATIVE_CLIENT_AUTH_V1', 'TENANT_COMPACT_LINEAGE_V1', 'TENANT_AUTHORITY_SET_V1', 'TENANT_MATERIAL_HISTORY_V1'] : [...tenantCoreReadCapabilities, 'TENANT_NATIVE_CLIENT_AUTH_V1', 'TENANT_COMPACT_LINEAGE_V1', 'TENANT_AUTHORITY_SET_V1', 'TENANT_MATERIAL_HISTORY_V1'],
|
|
11
11
|
tenantProviders: component === 'core' ? [16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26] : [], requiredCoreProviders: component === 'admin-web' ? [20] : [],
|
|
12
12
|
budgetReadVersions: component === 'core' ? [2] : [], budgetMigrationVersions: component === 'core' ? [1] : [] };
|
|
13
13
|
}
|
|
@@ -16,7 +16,7 @@ export function assertRuntimeFormatCompatibility(raw, facts, component, mode) {
|
|
|
16
16
|
const fail = (code) => { throw new Error('RUNTIME_COMPATIBILITY_' + code); };
|
|
17
17
|
if (!['core', 'admin-web'].includes(component) || !['INSTALL', 'START', 'ROLLBACK', 'RECOVERY'].includes(mode))
|
|
18
18
|
fail('CONTEXT_INVALID');
|
|
19
|
-
if (!Number.isSafeInteger(facts.identityVersion) || facts.identityVersion < 11 || facts.identityVersion >
|
|
19
|
+
if (!Number.isSafeInteger(facts.identityVersion) || facts.identityVersion < 11 || facts.identityVersion > 24)
|
|
20
20
|
fail('IDENTITY_UNSUPPORTED');
|
|
21
21
|
if (facts.budgetVersion !== null && ![1, 2].includes(facts.budgetVersion))
|
|
22
22
|
fail('BUDGET_UNSUPPORTED');
|
|
@@ -30,7 +30,7 @@ export function assertRuntimeFormatCompatibility(raw, facts, component, mode) {
|
|
|
30
30
|
const value = raw, expected = runtimeCompatibility(component), keys = Object.keys(expected);
|
|
31
31
|
if (Object.keys(value).length !== keys.length || Object.keys(value).some(key => !keys.includes(key)) || value.schemaVersion !== 1 || value.component !== component)
|
|
32
32
|
fail('DECLARATION_INVALID');
|
|
33
|
-
if (!Number.isSafeInteger(value.identityReadMinimum) || !Number.isSafeInteger(value.identityReadMaximum) || value.identityReadMinimum < 11 || value.identityReadMaximum >
|
|
33
|
+
if (!Number.isSafeInteger(value.identityReadMinimum) || !Number.isSafeInteger(value.identityReadMaximum) || value.identityReadMinimum < 11 || value.identityReadMaximum > 24 || value.identityReadMinimum > value.identityReadMaximum)
|
|
34
34
|
fail('DECLARATION_INVALID');
|
|
35
35
|
for (const key of ['capabilities', 'tenantProviders', 'requiredCoreProviders', 'budgetReadVersions', 'budgetMigrationVersions']) {
|
|
36
36
|
const list = value[key], allowed = expected[key];
|
|
@@ -39,7 +39,7 @@ export function assertRuntimeFormatCompatibility(raw, facts, component, mode) {
|
|
|
39
39
|
}
|
|
40
40
|
if (facts.identityVersion < value.identityReadMinimum || facts.identityVersion > value.identityReadMaximum)
|
|
41
41
|
fail('IDENTITY_UNSUPPORTED');
|
|
42
|
-
if (facts.identityVersion >= 12 && expected.capabilities.some(cap => (facts.identityVersion >= 21 || cap !== 'TENANT_NATIVE_CLIENT_AUTH_V1') && !value.capabilities.includes(cap)))
|
|
42
|
+
if (facts.identityVersion >= 12 && expected.capabilities.some(cap => (facts.identityVersion >= 21 || cap !== 'TENANT_NATIVE_CLIENT_AUTH_V1') && (facts.identityVersion >= 22 || cap !== 'TENANT_COMPACT_LINEAGE_V1') && (facts.identityVersion >= 23 || cap !== 'TENANT_AUTHORITY_SET_V1') && (facts.identityVersion >= 24 || cap !== 'TENANT_MATERIAL_HISTORY_V1') && !value.capabilities.includes(cap)))
|
|
43
43
|
fail('CAPABILITY_REQUIRED');
|
|
44
44
|
// New Provider21/22 are advertised, but historical Identity >=12 does not imply the new opt-in writer.
|
|
45
45
|
if (facts.identityVersion >= 12 && ['tenantProviders', 'requiredCoreProviders'].some(key => (key === 'tenantProviders' && component === 'core' ? [16, 17, 18, 19, 20] : expected[key]).some(version => !value[key].includes(version))))
|
|
@@ -18,10 +18,7 @@ export const knowledgeMcpProviderContractSchema = z.object({
|
|
|
18
18
|
/** 版本化元数据只声明实际启用的协议;保留严格 v1,避免旧消费者误认新增生命周期。 */
|
|
19
19
|
const providerV2BaseSchema = knowledgeMcpProviderContractSchema.omit({ schemaVersion: true, protocolVersion: true }).extend({
|
|
20
20
|
schemaVersion: z.literal(2), defaultProtocolVersion: z.literal(knowledgeMcpProtocolVersion),
|
|
21
|
-
protocols: z.array(z.
|
|
22
|
-
z.object({ version: z.literal('2026-07-28'), lifecycle: z.literal('STATELESS_DISCOVERY'), transport: z.literal('STREAMABLE_HTTP') }).strict(),
|
|
23
|
-
z.object({ version: z.literal('2025-06-18'), lifecycle: z.literal('INITIALIZE'), transport: z.literal('STREAMABLE_HTTP') }).strict(),
|
|
24
|
-
])).min(1).max(2),
|
|
21
|
+
protocols: z.array(z.object({ version: z.literal('2026-07-28'), lifecycle: z.literal('STATELESS_DISCOVERY'), transport: z.literal('STREAMABLE_HTTP') }).strict()).length(1),
|
|
25
22
|
}).strict();
|
|
26
23
|
export const knowledgeMcpProviderContractV2Schema = providerV2BaseSchema.superRefine((value, ctx) => {
|
|
27
24
|
const versions = value.protocols.map(p => p.version);
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
// Data-only Native HTTP projection. EventSDK remains the server-side protocol validator.
|
|
3
|
+
const atom = (max = 256) => z.string().min(1).max(max).regex(/^[^\u0000-\u0020\u007f]+$/);
|
|
4
|
+
const uri = z.string().url().max(2048), positive = z.number().int().min(1).max(2147483647), generation = z.number().int().min(0).max(2147483647);
|
|
5
|
+
export const tenantMaterialEventType = 'io.nativeknowledge.tenant-material.changed.v1';
|
|
6
|
+
export const tenantEventSourceSchema = z.object({ source: uri, serviceRef: atom(), tenantRef: atom(), issuer: uri, subject: atom() }).strict();
|
|
7
|
+
export const tenantEventRegistrationSchema = z.object({ schemaVersion: z.literal(1), requestId: atom(), expectedRevision: positive.nullable(), source: tenantEventSourceSchema, target: z.object({ serviceRef: atom(), tenantRef: atom() }).strict(), grant: z.object({ grantRef: atom(), version: positive, eventType: atom().regex(/^[A-Za-z0-9][A-Za-z0-9._-]*\.v[1-9][0-9]*$/), consumerRef: atom() }).strict(), status: z.enum(['ACTIVE', 'REVOKED']) }).strict();
|
|
8
|
+
export const tenantEventOutboxRecoverySchema = z.object({ schemaVersion: z.literal(1), requestId: atom(), source: uri, id: atom(), deliveryid: z.string().regex(/^[a-f0-9]{64}$/), expectedGeneration: generation }).strict();
|
|
9
|
+
export const tenantEventGapRecoverySchema = z.object({ schemaVersion: z.literal(1), requestId: atom(), connectionRef: atom(128), expectedCursor: atom(), expectedOldestAvailableCursor: atom() }).strict();
|
|
10
|
+
const directoryPage = z.object({ connectionRef: atom(128), after: z.string().max(2048).optional(), limit: z.number().int().min(1).max(100).optional() }).strict();
|
|
11
|
+
const receiptInput = z.object({ requestId: atom() }).strict();
|
|
12
|
+
export const tenantEventToolSchemas = {
|
|
13
|
+
tenant_event_materials: directoryPage,
|
|
14
|
+
tenant_event_connection_status: z.object({}).strict(),
|
|
15
|
+
tenant_event_exchange_get: z.object({ connectionRef: atom(128) }).strict(),
|
|
16
|
+
tenant_event_exchange_list: z.object({ after: z.string().max(256).optional(), limit: z.number().int().min(1).max(100).optional() }).strict(),
|
|
17
|
+
tenant_event_exchange_configure: tenantEventRegistrationSchema,
|
|
18
|
+
tenant_event_exchange_receipt: receiptInput,
|
|
19
|
+
tenant_event_outbox_list: z.object({ after: z.number().int().nonnegative().optional(), limit: z.number().int().min(1).max(100).optional() }).strict(),
|
|
20
|
+
tenant_event_outbox_recover: tenantEventOutboxRecoverySchema,
|
|
21
|
+
tenant_event_outbox_recovery_receipt: receiptInput,
|
|
22
|
+
tenant_event_gap_recover: tenantEventGapRecoverySchema,
|
|
23
|
+
tenant_event_gap_recovery_receipt: receiptInput,
|
|
24
|
+
tenant_event_gap_baseline_read: z.object({ baselineRef: uri }).strict(),
|
|
25
|
+
};
|
|
26
|
+
export const tenantEventReadTools = new Set(['tenant_event_materials', 'tenant_event_connection_status', 'tenant_event_exchange_get', 'tenant_event_exchange_list', 'tenant_event_exchange_receipt', 'tenant_event_outbox_list', 'tenant_event_outbox_recovery_receipt', 'tenant_event_gap_recovery_receipt', 'tenant_event_gap_baseline_read']);
|
|
27
|
+
export const tenantEventWorkerSchema = z.object({ schemaVersion: z.literal(1), status: z.enum(['DISABLED', 'CONNECTED', 'RECONNECTING', 'STOPPED']), connected: z.boolean(), at: z.string().datetime(), revision: z.string().optional(), stale: z.boolean() }).strict();
|
|
28
|
+
const route = z.object({ connectionRef: atom(128), tenantId: atom(), revision: positive, binding: tenantEventRegistrationSchema }).strict();
|
|
29
|
+
const exchangeResult = z.object({ schemaVersion: z.literal(1), connectionRef: atom(128), revision: positive, status: z.enum(['ACTIVE', 'REVOKED']), grantRef: atom(), grantVersion: positive }).strict();
|
|
30
|
+
const baseline = z.object({ schemaVersion: z.literal(1), baselineRef: uri, source: uri, sourceTenant: atom(), targetService: atom(), targetTenant: atom(), connectionRef: atom(128), grantRef: atom(), grantVersion: positive, previousWatermark: atom(), retainedThrough: atom(), watermark: atom(), sourceRevision: atom(), createdAt: z.string().datetime(), readModel: z.literal('AUTHORITATIVE_ON_DEMAND'), directoryRef: uri }).strict();
|
|
31
|
+
const outboxResult = z.object({ schemaVersion: z.literal(1), requestId: atom(), source: uri, id: atom(), deliveryid: z.string().regex(/^[a-f0-9]{64}$/), status: z.literal('REQUEUED'), generation: positive, previousOutcome: z.json().nullable(), attempt: z.number().int().nonnegative() }).strict();
|
|
32
|
+
const gapResult = z.object({ schemaVersion: z.literal(1), requestId: atom(), status: z.literal('BASELINE_STAGED'), baseline, event: z.object({ source: uri, id: atom(), deliveryid: z.string().regex(/^[a-f0-9]{64}$/) }).strict(), checkpoint: z.object({ previous: atom(), current: atom() }).strict() }).strict();
|
|
33
|
+
const receipt = (result) => z.object({ schemaVersion: z.literal(1), requestId: atom(), result: result.nullable() }).strict();
|
|
34
|
+
export const tenantEventResultSchemas = {
|
|
35
|
+
tenant_event_materials: z.object({ schemaVersion: z.literal(1), connectionRef: atom(128), resourceAccess: z.object({ providerPath: z.literal('/v16/provider'), tools: z.tuple([z.literal('knowledge_resource_describe'), z.literal('knowledge_resource_read')]) }).strict(), items: z.array(z.object({ ref: uri, title: z.string().max(4096) }).strict()).max(100), nextAfter: uri.nullable() }).strict(),
|
|
36
|
+
tenant_event_connection_status: z.object({ schemaVersion: z.literal(1), configuration: z.enum(['DISABLED', 'PROFILE_VALID', 'INVALID']), mode: z.enum(['DISABLED', 'SHADOW', 'ACTIVE']).nullable(), source: tenantEventSourceSchema.nullable(), relay: z.enum(['NOT_CONFIGURED', 'AVAILABLE', 'UNAVAILABLE']), worker: tenantEventWorkerSchema.nullable(), eventType: z.literal(tenantMaterialEventType), counterpartAcceptance: z.literal('NOT_OBSERVED') }).strict(),
|
|
37
|
+
tenant_event_exchange_get: z.object({ schemaVersion: z.literal(1), item: route.nullable() }).strict(),
|
|
38
|
+
tenant_event_exchange_list: z.object({ schemaVersion: z.literal(1), items: z.array(route).max(100), nextAfter: z.string().max(256).nullable() }).strict(),
|
|
39
|
+
tenant_event_exchange_configure: exchangeResult,
|
|
40
|
+
tenant_event_exchange_receipt: receipt(exchangeResult),
|
|
41
|
+
tenant_event_outbox_list: z.object({ schemaVersion: z.literal(1), items: z.array(z.object({ source: uri, id: atom(), deliveryid: z.string().regex(/^[a-f0-9]{64}$/), status: z.enum(['PENDING', 'UNKNOWN', 'PUBLISHED', 'HOLD']), generation, attempt: z.number().int().nonnegative(), nextAttemptAt: z.number().int().nonnegative(), reasonCode: z.string().max(256).nullable() }).strict()).max(100), nextAfter: z.number().int().nonnegative().nullable(), gaps: z.array(z.object({ route_key: atom(), connectionRef: atom(128), cursor: atom(), gap_oldest: atom() }).strict()).max(100), worker: tenantEventWorkerSchema.nullable() }).strict(),
|
|
42
|
+
tenant_event_outbox_recover: outboxResult,
|
|
43
|
+
tenant_event_outbox_recovery_receipt: receipt(outboxResult),
|
|
44
|
+
tenant_event_gap_recover: gapResult,
|
|
45
|
+
tenant_event_gap_recovery_receipt: receipt(gapResult),
|
|
46
|
+
tenant_event_gap_baseline_read: z.object({ schemaVersion: z.literal(1), baseline: baseline.nullable() }).strict(),
|
|
47
|
+
};
|
|
48
|
+
export function tenantEventEnvelopeSchema(tool) { return z.object({ schemaVersion: z.literal(27), tenantId: atom(), tool: z.literal(tool), data: tenantEventResultSchemas[tool] }).strict(); }
|
|
49
|
+
export const tenantEventErrorCodes = ['EVENTSDK_OPERATION_RESULT_UNKNOWN', 'TENANT_MANAGEMENT_AUTHORITY_CHANGED', 'TENANT_MANAGEMENT_FORBIDDEN', 'EVENTSDK_INVALID_INPUT', 'EVENTSDK_SOURCE_NOT_CONFIGURED', 'EVENTSDK_RELAY_NOT_CONFIGURED', 'EVENTSDK_EXCHANGE_UNAVAILABLE', 'EVENTSDK_REQUEST_ID_CONFLICT', 'EVENTSDK_EXCHANGE_REVISION_CONFLICT', 'EVENTSDK_GRANT_VERSION_CONFLICT', 'EVENTSDK_GAP_CONFLICT', 'RECOVERY_REQUIRED', 'STALE_LEASE', 'EVENTSDK_GAP_SOURCE_CHANGED', 'TENANT_MANAGEMENT_INPUT_BUDGET'];
|
|
50
|
+
export const tenantEventErrorSchema = z.object({ errorCode: z.enum(tenantEventErrorCodes) }).strict();
|
|
51
|
+
export const tenantEventInputJsonSchemas = Object.fromEntries(Object.entries(tenantEventToolSchemas).map(([name, schema]) => [name, z.toJSONSchema(schema, { target: 'draft-07' })]));
|
|
52
|
+
export const tenantEventOutputJsonSchemas = Object.fromEntries(Object.keys(tenantEventToolSchemas).map(name => [name, z.toJSONSchema(tenantEventEnvelopeSchema(name), { target: 'draft-07' })]));
|
|
53
|
+
export const tenantEventProviderSchema = z.object({ schemaVersion: z.literal(27), authorityVersion: z.literal(2), requiredScope: z.literal('knowledge.material.route'), readScope: z.literal('knowledge.material.read'), resource: uri, callEndpoint: uri, mcpEndpoint: uri, tools: z.array(z.object({ name: z.enum(Object.keys(tenantEventToolSchemas)), description: z.string(), inputSchema: z.json(), outputSchema: z.json(), annotations: z.object({ readOnlyHint: z.boolean(), destructiveHint: z.boolean(), idempotentHint: z.boolean(), openWorldHint: z.boolean() }).strict(), _meta: z.object({ 'native-knowledge/requiredScope': z.enum(['knowledge.material.route', 'knowledge.material.read']) }).strict() }).strict()).max(32) }).strict();
|
|
54
|
+
/** Native event-link/1 handoff, separate from EventSDK transport contracts. */
|
|
55
|
+
export const tenantEventLinkProposalSchema = z.object({ schemaVersion: z.literal(1), requestId: atom(), source: tenantEventSourceSchema, target: tenantEventRegistrationSchema.shape.target, grant: tenantEventRegistrationSchema.shape.grant, connectionRef: atom(128), targetDisplayName: z.string().min(1).max(160), approvalRef: atom(), expiresAt: z.string().datetime() }).strict();
|
|
56
|
+
export const tenantEventLinkCatalogSchema = z.object({ schemaVersion: z.literal(1), applications: z.array(z.object({ id: atom(64), name: z.string().min(1).max(80), serviceRef: atom(), origin: z.string().url().max(512), clientId: atom(128), consumerRef: atom().optional() }).strict()).max(8) }).strict();
|
|
57
|
+
export function tenantEventToolScope(name) { return name === 'tenant_event_materials' ? 'knowledge.material.read' : 'knowledge.material.route'; }
|
|
@@ -75,7 +75,7 @@ export const tenantManagementErrorSchema = z.object({ errorCode: tenantManagemen
|
|
|
75
75
|
export function tenantManagementEnvelopeSchema(tool) { return z.object({ schemaVersion: z.literal(2), tenantId: materialTenantIdSchema, tool: z.literal(tool), data: tenantManagementDataSchemas[tool] }).strict(); }
|
|
76
76
|
export const tenantManagementInputJsonSchemas = Object.fromEntries(Object.entries(tenantManagementToolSchemas).map(([name, schema]) => [name, z.toJSONSchema(schema, { target: 'draft-07' })]));
|
|
77
77
|
export const tenantManagementOutputJsonSchemas = Object.fromEntries(Object.keys(tenantManagementToolSchemas).map(name => [name, { type: 'object', oneOf: [z.toJSONSchema(tenantManagementEnvelopeSchema(name), { target: 'draft-07' }), z.toJSONSchema(tenantManagementErrorSchema, { target: 'draft-07' })] }]));
|
|
78
|
-
export const tenantManagementProviderBaseSchema = z.object({ schemaVersion: z.literal(17), provider: z.literal('knowledge-v2'), codeRevision: z.string().min(1).max(128), authorityVersion: z.literal(2), context: z.literal('TENANT_EXPLICIT_MANAGEMENT_V1'), managementConfigured: z.boolean(), resource: stableUriSchema, issuer: stableUriSchema, authorizationEndpoint: stableUriSchema, tokenEndpoint: stableUriSchema, revocationEndpoint: stableUriSchema, mcpEndpoint: stableUriSchema, callEndpoint: stableUriSchema, contentEndpoint: stableUriSchema, contentContextHeader: z.literal('x-knowledge-tenant-id'), legacyProviderEndpoint: stableUriSchema, protocols: z.array(z.
|
|
78
|
+
export const tenantManagementProviderBaseSchema = z.object({ schemaVersion: z.literal(17), provider: z.literal('knowledge-v2'), codeRevision: z.string().min(1).max(128), authorityVersion: z.literal(2), context: z.literal('TENANT_EXPLICIT_MANAGEMENT_V1'), managementConfigured: z.boolean(), resource: stableUriSchema, issuer: stableUriSchema, authorizationEndpoint: stableUriSchema, tokenEndpoint: stableUriSchema, revocationEndpoint: stableUriSchema, mcpEndpoint: stableUriSchema, callEndpoint: stableUriSchema, contentEndpoint: stableUriSchema, contentContextHeader: z.literal('x-knowledge-tenant-id'), legacyProviderEndpoint: stableUriSchema, protocols: z.array(z.literal('2026-07-28')).length(1), tools: z.array(z.string()).length(Object.keys(tenantManagementToolSchemas).length), requestMaxBytes: z.literal(131072), resultMaxBytes: z.literal(524288), submissionMaxBytes: z.literal(65536), inlineContentMaxBytes: z.literal(32768), contentReadMaxBytes: z.literal(16777216), collectionMode: z.literal('MANUAL_ONLY_OAUTH'), capabilities: z.tuple([z.literal('TENANT_MANAGEMENT_V1'), z.literal('TENANT_WORKFLOW_V1'), z.literal('TENANT_CURRENTNESS_V2'), z.literal('TENANT_SOURCE_V1')]) }).strict();
|
|
79
79
|
export const tenantManagementProviderSchema = tenantManagementProviderBaseSchema.superRefine((v, ctx) => { if (new Set(v.tools).size !== Object.keys(tenantManagementToolSchemas).length || v.tools.some(name => !Object.hasOwn(tenantManagementToolSchemas, name)))
|
|
80
80
|
ctx.addIssue({ code: 'custom', message: 'Provider tools must match the exact native tool contract' }); });
|
|
81
81
|
/** 诊断 ref 只允许当前访问 Tenant 的 canonical 原生身份;不接受 URL/本机路径。 */
|
package/package.json
CHANGED
|
@@ -1,20 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@native-knowledge/cli",
|
|
3
|
-
"version": "0.1.0-rc.
|
|
3
|
+
"version": "0.1.0-rc.4",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
|
-
"description": "Remote Tenant CLI with OAuth and Agent-native discovery",
|
|
7
6
|
"engines": {
|
|
8
7
|
"node": ">=24"
|
|
9
8
|
},
|
|
10
9
|
"license": "Apache-2.0",
|
|
11
|
-
"repository": {
|
|
12
|
-
"type": "git",
|
|
13
|
-
"url": "git+https://github.com/SENLIN746/native-knowledge.git"
|
|
14
|
-
},
|
|
15
10
|
"files": [
|
|
16
11
|
"dist",
|
|
17
|
-
"README.md",
|
|
18
12
|
"LICENSE",
|
|
19
13
|
"NOTICE"
|
|
20
14
|
],
|
|
@@ -23,7 +17,7 @@
|
|
|
23
17
|
"knowledge-v2": "./dist/cli.js"
|
|
24
18
|
},
|
|
25
19
|
"dependencies": {
|
|
26
|
-
"@native-knowledge/knowledge-sdk": "0.1.0-rc.
|
|
20
|
+
"@native-knowledge/knowledge-sdk": "0.1.0-rc.4",
|
|
27
21
|
"zod": "^4.6.7"
|
|
28
22
|
}
|
|
29
|
-
}
|
|
23
|
+
}
|
package/README.md
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
# native-knowledge CLI
|
|
2
|
-
|
|
3
|
-
Remote Tenant and Agent-native client. Requires Node.js 24 or newer.
|
|
4
|
-
|
|
5
|
-
```sh
|
|
6
|
-
pnpm add --global @native-knowledge/cli@next
|
|
7
|
-
native-knowledge help
|
|
8
|
-
native-knowledge discover --server https://knowledge.example.com
|
|
9
|
-
native-knowledge auth login --server https://knowledge.example.com
|
|
10
|
-
native-knowledge auth whoami
|
|
11
|
-
native-knowledge tool list
|
|
12
|
-
native-knowledge auth logout
|
|
13
|
-
```
|
|
14
|
-
|
|
15
|
-
`knowledge-v2` is a compatible alias for the same remote client. stdout is one
|
|
16
|
-
JSON result; `--human` formats that result. `help` describes supported commands,
|
|
17
|
-
inputs and connection options. Agent discovery, typed tool calls and resource
|
|
18
|
-
downloads use the same server authorization as the SDK.
|
|
19
|
-
|
|
20
|
-
The service must admit the native public client and requested scopes. Browser
|
|
21
|
-
consent and PKCE bind the actual loopback callback. Tenant management additionally
|
|
22
|
-
requires current membership, client/audience delegation and runtime bindings;
|
|
23
|
-
successful login alone does not grant management authority.
|
|
24
|
-
|
|
25
|
-
Login creates private local profile and credential files. Do not copy credentials
|
|
26
|
-
into scripts, source control or shared configuration. Noninteractive business
|
|
27
|
-
commands do not open a browser or silently log in. Unknown mutation outcomes
|
|
28
|
-
require a read-only status check; do not blindly replay them.
|
|
29
|
-
|
|
30
|
-
The CLI does not open a business database, read local CAS, run collectors, use
|
|
31
|
-
SSH or expose Host maintenance. Retired local database flags and commands fail
|
|
32
|
-
before local business access. Install does not start services or collection.
|
|
33
|
-
|
|
34
|
-
Pin an exact qualified version for repeatable installs. Prereleases use `next`.
|
|
35
|
-
License: Apache-2.0. Historical MIT notices are retained in NOTICE.
|