@native-knowledge/cli 0.1.0-rc.1 → 0.1.0-rc.2
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 +202 -21
- package/NOTICE +29 -0
- package/README.md +26 -19
- package/dist/agent-entry-cli.js +88 -0
- package/dist/auth-commands.js +102 -0
- package/dist/cli.js +101 -4874
- package/dist/commands.js +17 -0
- package/dist/download.js +45 -0
- package/dist/errors.js +7 -0
- package/dist/input.js +89 -0
- package/dist/internal/contracts/artifact.js +103 -0
- package/dist/internal/contracts/collection-control.js +69 -0
- package/dist/internal/contracts/collection.js +174 -0
- package/dist/internal/contracts/common.js +16 -0
- package/dist/internal/contracts/currentness.js +221 -0
- package/dist/internal/contracts/event.js +35 -0
- package/dist/internal/contracts/evidence.js +171 -0
- package/dist/internal/contracts/index.js +54 -0
- package/dist/internal/contracts/material-capability.js +8 -0
- package/dist/internal/contracts/material-carrier.js +15 -0
- package/dist/internal/contracts/material-context.js +9 -0
- package/dist/internal/contracts/material-read.js +12 -0
- package/dist/internal/contracts/observation.js +39 -0
- package/dist/internal/contracts/persistence.js +239 -0
- package/dist/internal/contracts/project-intent.js +121 -0
- package/dist/internal/contracts/projection.js +194 -0
- package/dist/internal/contracts/public-reference.js +87 -0
- package/dist/internal/contracts/reference-record.js +55 -0
- package/dist/internal/contracts/remote-file.js +159 -0
- package/dist/internal/contracts/resource-scope.js +38 -0
- package/dist/internal/contracts/review-packet.js +61 -0
- package/dist/internal/contracts/review-plane.js +89 -0
- package/dist/internal/contracts/rich-document.js +184 -0
- package/dist/internal/contracts/runtime-compatibility.js +55 -0
- package/dist/internal/contracts/runtime.js +68 -0
- package/dist/internal/contracts/scheduler.js +256 -0
- package/dist/internal/contracts/signal.js +77 -0
- package/dist/internal/contracts/source-governance.js +194 -0
- package/dist/internal/contracts/source.js +32 -0
- package/dist/internal/contracts/tenant-budget.js +34 -0
- package/dist/internal/contracts/tenant-collection-request.js +58 -0
- package/dist/internal/contracts/tenant-collection.js +66 -0
- package/dist/internal/contracts/tenant-currentness.js +26 -0
- package/dist/internal/contracts/tenant-management.js +27 -0
- package/dist/internal/contracts/tenant-material-api.js +46 -0
- package/dist/internal/contracts/tenant-material-json-schema.js +16 -0
- package/dist/internal/contracts/tenant-pdf-text.js +13 -0
- package/dist/internal/contracts/tenant-project-control.js +19 -0
- package/dist/internal/contracts/tenant-public-reference.js +26 -0
- package/dist/internal/contracts/tenant-resource-api.js +70 -0
- package/dist/internal/contracts/tenant-resource.js +118 -0
- package/dist/internal/contracts/tenant-rich-document.js +17 -0
- package/dist/internal/contracts/tenant-source-binding.js +33 -0
- package/dist/internal/contracts/tenant-source-bridge.js +9 -0
- package/dist/internal/contracts/tenant-source-cutover.js +26 -0
- package/dist/internal/contracts/tenant-source-document.js +38 -0
- package/dist/internal/contracts/tenant-source-lease.js +5 -0
- package/dist/internal/contracts/tenant-source.js +83 -0
- package/dist/internal/contracts/tenant-web-collection.js +118 -0
- package/dist/internal/contracts/tenant-web-content-plan.js +39 -0
- package/dist/internal/contracts/tenant-web-content-result.js +15 -0
- package/dist/internal/contracts/tenant-web-content.js +16 -0
- package/dist/internal/contracts/tenant-web-crawl.js +55 -0
- package/dist/internal/contracts/tenant-web-dynamic.js +68 -0
- package/dist/internal/contracts/tenant-web-results.js +41 -0
- package/dist/internal/contracts/tenant-web-workflow.js +29 -0
- package/dist/internal/serving-contracts/agent-catalog.js +56 -0
- package/dist/internal/serving-contracts/agent-entry.js +57 -0
- package/dist/internal/serving-contracts/agent-guidance-shapes.js +12 -0
- package/dist/internal/serving-contracts/agent-input-hints.js +104 -0
- package/dist/internal/serving-contracts/body-search.js +16 -0
- package/dist/internal/serving-contracts/consumer.js +45 -0
- package/dist/internal/serving-contracts/core.js +76 -0
- package/dist/internal/serving-contracts/http.js +64 -0
- package/dist/internal/serving-contracts/index.js +25 -0
- package/dist/internal/serving-contracts/management.js +15 -0
- package/dist/internal/serving-contracts/material-capabilities.js +14 -0
- package/dist/internal/serving-contracts/material-index-status.js +5 -0
- package/dist/internal/serving-contracts/mcp.js +140 -0
- package/dist/internal/serving-contracts/tenant-governance.js +13 -0
- package/dist/internal/serving-contracts/tenant-management.js +89 -0
- package/dist/internal/serving-contracts/tenant-project.js +39 -0
- package/dist/internal/serving-contracts/tenant-runtime.js +37 -0
- package/dist/internal/serving-contracts/tenant-session.js +8 -0
- package/dist/internal/serving-contracts/tenant-web-content.js +20 -0
- package/dist/internal/serving-contracts/tenant-web-crawl.js +13 -0
- package/dist/internal/serving-contracts/tenant-web-dynamic.js +20 -0
- package/dist/internal/serving-contracts/tenant-web-workflow.js +36 -0
- package/dist/internal/serving-contracts/tenant-web.js +53 -0
- package/dist/internal/serving-contracts/tenant-workspace.js +28 -0
- package/dist/internal/serving-contracts/workflow.js +37 -0
- package/dist/profile-store.js +142 -0
- package/package.json +9 -13
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/** Provider21 增量能力;17–20 的注册表、默认版本和既有错误合同保持。 */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { tenantWebSpecSchema, tenantWebSummarySchema, tenantWebJobRefSchema, tenantWebSpecRevision, tenantCollectionCycleSchema, materialTenantIdSchema, tenantStorageKey, TENANT_WEB_SPEC_CAPABILITY } from '../contracts/index.js';
|
|
4
|
+
import { tenantRuntimeWorkspaceToolSchemas, tenantRuntimeWorkspaceDataSchemas, tenantRuntimeEnvelopeSchema, tenantRuntimeProviderSchema, tenantRuntimeScopesForInput, tenantRuntimeAuthorization } from './tenant-runtime.js';
|
|
5
|
+
import { tenantProjectErrorSchema } from './tenant-project.js';
|
|
6
|
+
import { tenantManagementSafeErrorRef } from './tenant-management.js';
|
|
7
|
+
export const tenantWebToolSchemas = {
|
|
8
|
+
tenant_web_collect_preview: z.object({ spec: tenantWebSpecSchema }).strict(),
|
|
9
|
+
tenant_web_collect_submit: z.object({ requestId: tenantCollectionCycleSchema, spec: tenantWebSpecSchema }).strict(),
|
|
10
|
+
tenant_web_collect_status: z.object({ jobRef: tenantWebJobRefSchema }).strict(),
|
|
11
|
+
};
|
|
12
|
+
export const tenantWebDataSchemas = {
|
|
13
|
+
tenant_web_collect_preview: z.object({ spec: tenantWebSpecSchema, specRevision: tenantWebSummarySchema.shape.specRevision, networkValidated: z.literal(false), budgetReserved: z.literal(false), execution: z.literal('UNAVAILABLE'), reason: z.literal('S2_NOT_IMPLEMENTED'), requirementsState: z.literal('DECLARED_NOT_EVALUATED') }).strict().superRefine((v, ctx) => { if (v.specRevision !== tenantWebSpecRevision(v.spec))
|
|
14
|
+
ctx.addIssue({ code: 'custom', message: 'Preview specification identity mismatch' }); }),
|
|
15
|
+
tenant_web_collect_submit: z.object({ inserted: z.boolean(), job: tenantWebSummarySchema }).strict(),
|
|
16
|
+
tenant_web_collect_status: tenantWebSummarySchema,
|
|
17
|
+
};
|
|
18
|
+
export const tenantWebWorkspaceToolSchemas = { ...tenantRuntimeWorkspaceToolSchemas, ...tenantWebToolSchemas };
|
|
19
|
+
export const tenantWebWorkspaceDataSchemas = { ...tenantRuntimeWorkspaceDataSchemas, ...tenantWebDataSchemas };
|
|
20
|
+
export const tenantWebErrorSchema = tenantProjectErrorSchema.extend({ completedPhase: z.enum([...tenantProjectErrorSchema.shape.completedPhase.unwrap().options, 'WEB_INTENT_PERSISTED']).optional() }).strict();
|
|
21
|
+
export function tenantWebSafeErrorRef(raw, tenantId) {
|
|
22
|
+
if (typeof raw === 'string' && new RegExp('^tenant-web-collection://' + tenantStorageKey(tenantId) + '/[a-f0-9]{64}$').test(raw))
|
|
23
|
+
return raw;
|
|
24
|
+
return tenantManagementSafeErrorRef(raw, tenantId);
|
|
25
|
+
}
|
|
26
|
+
export function tenantWebScopesForInput(name, raw) {
|
|
27
|
+
if (Object.hasOwn(tenantWebToolSchemas, name)) {
|
|
28
|
+
tenantWebToolSchemas[name].parse(raw);
|
|
29
|
+
return name === 'tenant_web_collect_status' ? ['knowledge.collect'] : ['knowledge.source.manage', 'knowledge.collect'];
|
|
30
|
+
}
|
|
31
|
+
return tenantRuntimeScopesForInput(name, raw);
|
|
32
|
+
}
|
|
33
|
+
export function tenantWebAuthorization(name) {
|
|
34
|
+
if (Object.hasOwn(tenantWebToolSchemas, name))
|
|
35
|
+
return { selection: 'FIXED', scopeAlternatives: [name === 'tenant_web_collect_status' ? ['knowledge.collect'] : ['knowledge.source.manage', 'knowledge.collect']] };
|
|
36
|
+
return tenantRuntimeAuthorization(name);
|
|
37
|
+
}
|
|
38
|
+
export function tenantWebEnvelopeSchema(tool) {
|
|
39
|
+
return z.object({ schemaVersion: z.literal(2), tenantId: materialTenantIdSchema, tool: z.literal(tool), data: tenantWebDataSchemas[tool] }).strict().superRefine((value, ctx) => {
|
|
40
|
+
const envelope = value, ref = envelope.data.jobRef ?? envelope.data.job?.jobRef;
|
|
41
|
+
if (ref && !ref.startsWith('tenant-web-collection://' + tenantStorageKey(envelope.tenantId) + '/'))
|
|
42
|
+
ctx.addIssue({ code: 'custom', message: 'Web intent must belong to the exact authenticated Tenant' });
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
export const tenantWebInputJsonSchemas = Object.fromEntries(Object.entries(tenantWebWorkspaceToolSchemas).map(([name, schema]) => [name, z.toJSONSchema(schema, { target: 'draft-07' })]));
|
|
46
|
+
export const tenantWebOutputJsonSchemas = Object.fromEntries(Object.keys(tenantWebWorkspaceToolSchemas).map(name => [name, { type: 'object', oneOf: [z.toJSONSchema(Object.hasOwn(tenantWebToolSchemas, name) ? tenantWebEnvelopeSchema(name) : tenantRuntimeEnvelopeSchema(name), { target: 'draft-07' }), z.toJSONSchema(tenantWebErrorSchema, { target: 'draft-07' })] }]));
|
|
47
|
+
export const tenantWebProviderSchema = z.object({ ...tenantRuntimeProviderSchema.shape,
|
|
48
|
+
schemaVersion: z.literal(21), tools: z.array(z.string()).length(Object.keys(tenantWebWorkspaceToolSchemas).length),
|
|
49
|
+
capabilities: z.tuple([z.literal('TENANT_MANAGEMENT_V1'), z.literal('TENANT_WORKFLOW_V1'), z.literal('TENANT_CURRENTNESS_V2'), z.literal('TENANT_SOURCE_V1'), z.literal('TENANT_WORKSPACE_METADATA_V1'), z.literal('TENANT_PROJECT_CONTEXT_V1'), z.literal('TENANT_RUNTIME_STATUS_V1'), z.literal(TENANT_WEB_SPEC_CAPABILITY)]),
|
|
50
|
+
}).strict().superRefine((value, ctx) => {
|
|
51
|
+
if (new Set(value.tools).size !== Object.keys(tenantWebWorkspaceToolSchemas).length || value.tools.some(name => !Object.hasOwn(tenantWebWorkspaceToolSchemas, name)))
|
|
52
|
+
ctx.addIssue({ code: 'custom', message: 'Provider21 tools must match the exact versioned registry' });
|
|
53
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Provider18 adds explicit metadata reads; Provider17 remains the exact original twenty tools. */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { tenantResourceRefSchema, tenantSourceIdSchema, collectionRefreshSchema, stableUriSchema, isoDateTimeSchema, materialTenantIdSchema } from '../contracts/index.js';
|
|
4
|
+
import { tenantManagementToolSchemas, tenantManagementDataSchemas, tenantManagementScopesForInput, tenantManagementAuthorization, tenantManagementProviderBaseSchema, tenantManagementErrorSchema } from './tenant-management.js';
|
|
5
|
+
const page = { after: z.string().min(1).max(4096).optional(), limit: z.number().int().min(1).max(100).optional() };
|
|
6
|
+
export const tenantWorkStageSchema = z.enum(['ALL', 'RESEARCH', 'DRAFT', 'READY_FOR_REVIEW', 'REWORK_REQUIRED', 'APPROVED']);
|
|
7
|
+
export const tenantWorkspaceExtraToolSchemas = { tenant_source_inventory: z.object(page).strict(), tenant_work_queue: z.object({ ...page, stage: tenantWorkStageSchema.default('ALL') }).strict() };
|
|
8
|
+
const source = z.object({ sourceId: tenantSourceIdSchema, title: z.string().min(1).max(512).nullable(), revisionRef: stableUriSchema.nullable(), generation: z.number().int().positive().safe().nullable(), paused: z.boolean().nullable(), tenantEnabled: z.boolean().nullable(), refresh: collectionRefreshSchema.nullable(), canonicalState: z.enum(['READY', 'UNAVAILABLE', 'INTEGRITY_MISMATCH']) }).strict();
|
|
9
|
+
const artifact = z.object({ ref: tenantResourceRefSchema, title: z.string().max(512), kind: z.string().max(128).nullable(), status: z.string().max(128).nullable(), version: z.number().int().positive().safe().nullable(), recordedAt: isoDateTimeSchema.nullable(), availability: z.enum(['READY', 'UNAVAILABLE', 'INTEGRITY_MISMATCH']), succession: z.enum(['SUCCESSOR_VISIBLE', 'NO_VISIBLE_SUCCESSOR', 'UNCONFIRMED']) }).strict();
|
|
10
|
+
export const tenantWorkspaceExtraDataSchemas = {
|
|
11
|
+
tenant_source_inventory: z.object({ items: z.array(source).max(100), nextAfter: z.string().max(4096).nullable(), coverage: z.literal('REGISTERED_TENANT_SOURCES') }).strict(),
|
|
12
|
+
tenant_work_queue: z.object({ items: z.array(artifact).max(100), nextAfter: z.string().max(4096).nullable(), stage: tenantWorkStageSchema, candidateCount: z.number().int().min(0).max(100), coverage: z.literal('AUTHORIZED_NATIVE_ARTIFACT_METADATA'), total: z.null() }).strict(),
|
|
13
|
+
};
|
|
14
|
+
export const tenantWorkspaceToolSchemas = { ...tenantManagementToolSchemas, ...tenantWorkspaceExtraToolSchemas };
|
|
15
|
+
export const tenantWorkspaceDataSchemas = { ...tenantManagementDataSchemas, ...tenantWorkspaceExtraDataSchemas };
|
|
16
|
+
export function tenantWorkspaceScopesForInput(name, raw) { if (name === 'tenant_source_inventory') {
|
|
17
|
+
tenantWorkspaceExtraToolSchemas[name].parse(raw);
|
|
18
|
+
return ['knowledge.source.read'];
|
|
19
|
+
} if (name === 'tenant_work_queue') {
|
|
20
|
+
tenantWorkspaceExtraToolSchemas[name].parse(raw);
|
|
21
|
+
return ['knowledge.workflow.read'];
|
|
22
|
+
} return tenantManagementScopesForInput(name, raw); }
|
|
23
|
+
export function tenantWorkspaceAuthorization(name) { return name === 'tenant_source_inventory' || name === 'tenant_work_queue' ? { selection: 'FIXED', scopeAlternatives: [[name === 'tenant_source_inventory' ? 'knowledge.source.read' : 'knowledge.workflow.read']] } : tenantManagementAuthorization(name); }
|
|
24
|
+
export function tenantWorkspaceEnvelopeSchema(tool) { return z.object({ schemaVersion: z.literal(2), tenantId: materialTenantIdSchema, tool: z.literal(tool), data: tenantWorkspaceDataSchemas[tool] }).strict(); }
|
|
25
|
+
export const tenantWorkspaceInputJsonSchemas = Object.fromEntries(Object.entries(tenantWorkspaceToolSchemas).map(([name, schema]) => [name, z.toJSONSchema(schema, { target: 'draft-07' })]));
|
|
26
|
+
export const tenantWorkspaceOutputJsonSchemas = Object.fromEntries(Object.keys(tenantWorkspaceToolSchemas).map(name => [name, { type: 'object', oneOf: [z.toJSONSchema(tenantWorkspaceEnvelopeSchema(name), { target: 'draft-07' }), z.toJSONSchema(tenantManagementErrorSchema, { target: 'draft-07' })] }]));
|
|
27
|
+
export const tenantWorkspaceProviderSchema = tenantManagementProviderBaseSchema.extend({ schemaVersion: z.literal(18), tools: z.array(z.string()).length(Object.keys(tenantWorkspaceToolSchemas).length), capabilities: z.tuple([z.literal('TENANT_MANAGEMENT_V1'), z.literal('TENANT_WORKFLOW_V1'), z.literal('TENANT_CURRENTNESS_V2'), z.literal('TENANT_SOURCE_V1'), z.literal('TENANT_WORKSPACE_METADATA_V1')]) }).strict().superRefine((value, ctx) => { if (new Set(value.tools).size !== Object.keys(tenantWorkspaceToolSchemas).length || value.tools.some(name => !Object.hasOwn(tenantWorkspaceToolSchemas, name)))
|
|
28
|
+
ctx.addIssue({ code: 'custom', message: 'Workspace tools must match the exact version18 contract' }); });
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/** Agent 的治理合同描述真实状态和下一步,不把写入权限解释为审核或正文权限。 */
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
import { artifactStatusSchema, idSchema, isoDateTimeSchema, publicationReadinessReportSchema, sha256Schema, stableUriSchema } from '../contracts/index.js';
|
|
4
|
+
import { consumerProjectRefSchema } from './consumer.js';
|
|
5
|
+
import { managementToolInputSchemas } from './management.js';
|
|
6
|
+
const project = z.object({ projectRef: consumerProjectRefSchema }).strict();
|
|
7
|
+
export const workflowPlanInputSchema = project.extend({ ref: stableUriSchema }).strict();
|
|
8
|
+
export const workflowGuideInputSchema = project;
|
|
9
|
+
export const workflowActionSchema = z.enum(['PREPARE_SOURCE', 'SUBMIT_REVIEW', 'FINALIZE_REVIEW', 'REGISTER']);
|
|
10
|
+
export const workflowAdvanceInputSchema = workflowPlanInputSchema.extend({ action: workflowActionSchema, expectedVersion: z.number().int().nonnegative().optional(), actedAt: isoDateTimeSchema.optional() }).strict().superRefine((value, ctx) => {
|
|
11
|
+
if (['SUBMIT_REVIEW', 'FINALIZE_REVIEW'].includes(value.action) && (!value.expectedVersion || !value.actedAt))
|
|
12
|
+
ctx.addIssue({ code: 'custom', message: 'transition requires exact expectedVersion and actedAt' });
|
|
13
|
+
});
|
|
14
|
+
export const agentSubmitInputSchema = project.extend({ sourceId: idSchema, contentBase64: z.string().min(1).max(87384), mediaType: z.string().trim().min(1).max(256), access: z.enum(['PUBLIC', 'TENANT', 'INTERNAL', 'FDE_INTERNAL']).default('TENANT'), submittedAt: isoDateTimeSchema.optional(), freshnessSeconds: z.number().int().min(60).max(86400).optional() }).strict();
|
|
15
|
+
const argumentsSchema = z.record(z.string(), z.json());
|
|
16
|
+
export const workflowNextActionSchema = z.object({ id: z.string(), tool: z.string().nullable(), arguments: argumentsSchema, requiredScopes: z.array(z.string()), missingScopes: z.array(z.string()), missingFields: z.array(z.string()), canExecute: z.boolean(), automatic: z.boolean(), reasonCode: z.string(), cli: z.object({ command: z.string(), flags: argumentsSchema }).strict(), http: z.object({ method: z.literal('POST'), path: z.literal('/mcp/management'), tool: z.string().nullable() }).strict() }).strict();
|
|
17
|
+
const readDecision = z.object({ action: z.enum(['ALLOW', 'REVIEW_REQUIRED', 'DENY']), reasonCodes: z.array(z.string()), authority: z.enum(['AUTHENTICATED_READER', 'LOCAL_PROFILE_SIMULATION']) }).strict();
|
|
18
|
+
export const workflowPlanSchema = z.object({ schemaVersion: z.literal(1), projectRef: consumerProjectRefSchema, ref: stableUriSchema, contentHash: sha256Schema, kind: z.string(), version: z.number().int().positive().nullable(), status: artifactStatusSchema.or(z.enum(['RAW_EVIDENCE', 'RAW_MATERIAL'])), productionPhase: z.enum(['PERSISTED', 'CATALOG_PROJECTED', 'REGISTERED']), rawMaterialAvailable: z.boolean().nullable(), readiness: publicationReadinessReportSchema.nullable(), reviewRef: stableUriSchema.nullable(), reviewDecision: z.enum(['PASS', 'REWORK', 'REJECT']).nullable(), support: z.object({ action: z.enum(['ALLOW', 'REVIEW_REQUIRED', 'DENY']), reasonCodes: z.array(z.string()), missingEvidenceRefs: z.array(stableUriSchema) }).strict().nullable(), governedPolicyReady: z.boolean(), consumerReadDecision: readDecision.nullable(), externalReady: z.boolean(), successorRef: stableUriSchema.nullable(), blockers: z.array(z.string()), nextActions: z.array(workflowNextActionSchema).max(70) }).strict();
|
|
19
|
+
export const workflowAdvanceResultSchema = z.object({ schemaVersion: z.literal(1), action: workflowActionSchema, previousRef: stableUriSchema, inserted: z.boolean(), plan: workflowPlanSchema }).strict();
|
|
20
|
+
export const workflowErrorSchema = z.object({ errorCode: z.string(), completedPhase: z.enum(['VALIDATED', 'PERSISTED', 'CATALOG_PROJECTED', 'REGISTERED']).optional(), ref: stableUriSchema.optional() }).strict();
|
|
21
|
+
export const workflowToolInputSchemas = { knowledge_workflow_guide: z.toJSONSchema(workflowGuideInputSchema, { target: 'draft-07' }), knowledge_workflow_plan: z.toJSONSchema(workflowPlanInputSchema, { target: 'draft-07' }), knowledge_workflow_advance: z.toJSONSchema(workflowAdvanceInputSchema, { target: 'draft-07' }), knowledge_agent_submit: z.toJSONSchema(agentSubmitInputSchema, { target: 'draft-07' }) };
|
|
22
|
+
export const workflowToolScopes = { knowledge_workflow_guide: 'knowledge.workflow.read', knowledge_workflow_plan: 'knowledge.workflow.read', knowledge_workflow_advance: 'knowledge.workflow.read', knowledge_agent_submit: 'knowledge.material.write' };
|
|
23
|
+
export const workflowActionScopes = { PREPARE_SOURCE: 'knowledge.compose', SUBMIT_REVIEW: 'knowledge.compose', FINALIZE_REVIEW: 'knowledge.approve', REGISTER: 'knowledge.material.write' };
|
|
24
|
+
/** 网络成功和失败共享可发现 schema,阶段包含已经完成注册后的尾部失败。 */
|
|
25
|
+
export const agentSubmitResultSchema = z.object({ schemaVersion: z.literal(1), production: z.object({ phase: z.enum(['CATALOG_PROJECTED', 'REGISTERED']), ref: stableUriSchema, registered: z.boolean(), identity: z.enum(['CONFIGURED', 'NOT_CONFIGURED']) }).strict(), presentation: z.object({ documentRef: stableUriSchema, inserted: z.boolean(), contentHash: sha256Schema }).strict().nullable(), evidenceRef: stableUriSchema, projectRef: consumerProjectRefSchema, contentHash: sha256Schema, byteLength: z.number().int().min(1).max(65536), inserted: z.boolean(), lifecycle: z.literal('QUEUED'), contentClass: z.literal('RAW_EVIDENCE'), nextStep: z.object({ tool: z.literal('knowledge_workflow_plan'), arguments: workflowPlanInputSchema }).strict() }).strict();
|
|
26
|
+
const guideSchema = z.object({ schemaVersion: z.literal(1), model: z.record(z.string(), z.json()), rules: z.array(z.string()), tools: z.record(z.string(), z.object({ requiredScope: z.string(), inputSchema: z.json() }).strict()), advanceScopes: z.record(z.string(), z.string()), https: z.json() }).strict();
|
|
27
|
+
const output = (success) => ({ type: 'object', oneOf: [z.toJSONSchema(success, { target: 'draft-07' }), z.toJSONSchema(workflowErrorSchema, { target: 'draft-07' })] });
|
|
28
|
+
export const workflowToolOutputSchemas = { knowledge_workflow_guide: output(guideSchema), knowledge_workflow_plan: output(workflowPlanSchema), knowledge_workflow_advance: output(workflowAdvanceResultSchema), knowledge_agent_submit: output(agentSubmitResultSchema) };
|
|
29
|
+
/** 同一份模型与参数 schema 供 CLI、MCP guide 和文档示例使用;不给 review 默认 PASS。 */
|
|
30
|
+
export function workflowGuide() {
|
|
31
|
+
const tools = {};
|
|
32
|
+
for (const [name, schema] of Object.entries(workflowToolInputSchemas))
|
|
33
|
+
tools[name] = { requiredScope: workflowToolScopes[name], inputSchema: schema };
|
|
34
|
+
for (const [name, schema] of Object.entries(managementToolInputSchemas))
|
|
35
|
+
tools[name] = { requiredScope: name === 'knowledge_review' ? 'knowledge.review' : name === 'knowledge_finalize_review' ? 'knowledge.approve' : 'knowledge.compose', inputSchema: schema };
|
|
36
|
+
return { schemaVersion: 1, model: { raw: 'Evidence / Material 保留原字节和 provenance;原文可读不等于结论已审核。', reviewed: 'KNOWLEDGE / INSIGHT', lifecycle: ['DRAFT', 'READY_FOR_REVIEW', 'REVIEW(PASS|REWORK|REJECT)', 'APPROVED|REWORK_REQUIRED|REJECTED'], publication: ['PERSISTED', 'CATALOG_PROJECTED', 'REGISTERED', 'consumer read ALLOW'] }, rules: ['先调用 knowledge_workflow_plan,再执行 canExecute 动作;缺字段由 Agent 补齐并重新计划。', '读取原文、核对引用和适用范围后,获授权 reviewer 显式写 PASS / REWORK / REJECT;不根据写入成功推断 PASS。', 'RESEARCH 先正式合成为 KNOWLEDGE / INSIGHT;Claim Currentness proposal 使用专门审核链。', 'freshnessSeconds 仅为作者在系统内首次保存的精确快照时效,不证明外部网页已复核;同身份重放不延长时效。', 'externalReady 需要注册、治理门通过及当前已鉴权消费者实际 read ALLOW;CLI profile 是模拟。', 'Plan 不提供正文或 Review summary;审核时使用独立 read scope 读取 exact ref。'], tools, advanceScopes: workflowActionScopes, https: { method: 'POST', path: '/mcp/management', body: { tool: 'tool name', arguments: '对应 inputSchema' }, authorization: 'OAuth Bearer + client/project binding;API key 不授予管理权限' } };
|
|
37
|
+
}
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/** 客户端只持久化私有配置与凭据,不包含资料或运行数据库。 */
|
|
2
|
+
import { open, mkdir, lstat, rename, unlink } from 'node:fs/promises';
|
|
3
|
+
import { constants } from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { randomBytes } from 'node:crypto';
|
|
6
|
+
import { AuthError } from '@native-knowledge/knowledge-sdk';
|
|
7
|
+
export class ProfileStore {
|
|
8
|
+
root;
|
|
9
|
+
constructor(root) {
|
|
10
|
+
this.root = root;
|
|
11
|
+
if (!path.isAbsolute(root))
|
|
12
|
+
throw new AuthError('AUTH_CONFIG_PATH_INVALID');
|
|
13
|
+
}
|
|
14
|
+
name(name) { if (!/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/.test(name))
|
|
15
|
+
throw new AuthError('AUTH_PROFILE_INVALID'); return name; }
|
|
16
|
+
async directory(create = false) { if (create)
|
|
17
|
+
await mkdir(this.root, { recursive: true, mode: 0o700 }); let s; try {
|
|
18
|
+
s = await lstat(this.root);
|
|
19
|
+
}
|
|
20
|
+
catch (e) {
|
|
21
|
+
if (e.code === 'ENOENT' && !create)
|
|
22
|
+
return false;
|
|
23
|
+
throw e;
|
|
24
|
+
} if (!s.isDirectory() || s.isSymbolicLink() || s.uid !== process.getuid?.() || (s.mode & 0o077) !== 0)
|
|
25
|
+
throw new AuthError('AUTH_CONFIG_PERMISSIONS'); return true; }
|
|
26
|
+
async read(name) {
|
|
27
|
+
if (!await this.directory())
|
|
28
|
+
return null;
|
|
29
|
+
let h;
|
|
30
|
+
try {
|
|
31
|
+
h = await open(path.join(this.root, name), constants.O_RDONLY | constants.O_NOFOLLOW);
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
if (e.code === 'ENOENT')
|
|
35
|
+
return null;
|
|
36
|
+
throw new AuthError('AUTH_CONFIG_PERMISSIONS');
|
|
37
|
+
}
|
|
38
|
+
try {
|
|
39
|
+
const s = await h.stat();
|
|
40
|
+
if (!s.isFile() || s.uid !== process.getuid?.() || (s.mode & 0o077) !== 0 || s.size > 65536)
|
|
41
|
+
throw new AuthError('AUTH_CONFIG_PERMISSIONS');
|
|
42
|
+
return JSON.parse(await h.readFile('utf8'));
|
|
43
|
+
}
|
|
44
|
+
catch (e) {
|
|
45
|
+
if (e instanceof AuthError)
|
|
46
|
+
throw e;
|
|
47
|
+
throw new AuthError('AUTH_CONFIG_INVALID');
|
|
48
|
+
}
|
|
49
|
+
finally {
|
|
50
|
+
await h.close();
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async write(name, value) { await this.directory(true); const temp = path.join(this.root, '.write-' + randomBytes(16).toString('hex')), h = await open(temp, 'wx', 0o600); try {
|
|
54
|
+
await h.writeFile(JSON.stringify(value));
|
|
55
|
+
await h.sync();
|
|
56
|
+
await h.close();
|
|
57
|
+
await rename(temp, path.join(this.root, name));
|
|
58
|
+
const d = await open(this.root, 'r');
|
|
59
|
+
try {
|
|
60
|
+
await d.sync();
|
|
61
|
+
}
|
|
62
|
+
finally {
|
|
63
|
+
await d.close();
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
catch (e) {
|
|
67
|
+
await h.close().catch(() => { });
|
|
68
|
+
await unlink(temp).catch(() => { });
|
|
69
|
+
throw e;
|
|
70
|
+
} }
|
|
71
|
+
async config() { const c = await this.read('profiles.json') ?? { version: 1, selected: null, profiles: {} }; if (c.version !== 1 || !c.profiles || Array.isArray(c.profiles) || typeof c.profiles !== 'object' || c.selected !== null && typeof c.selected !== 'string')
|
|
72
|
+
throw new AuthError('AUTH_CONFIG_INVALID'); return c; }
|
|
73
|
+
async selected(explicit) { const c = await this.config(), name = explicit ?? c.selected; if (!name || !Object.hasOwn(c.profiles, this.name(name)))
|
|
74
|
+
throw new AuthError('AUTH_REQUIRED'); return { name, profile: c.profiles[name] }; }
|
|
75
|
+
async secret(name) { const s = await this.read(this.name(name) + '.secret.json'); if (s && (!Number.isSafeInteger(s.generation) || s.generation < 1 || !['READY', 'REFRESH_PENDING', 'REAUTH_REQUIRED'].includes(s.state) || typeof s.expiresAt !== 'string' || !Number.isFinite(Date.parse(s.expiresAt)) || !/^[-\w]{43}$/.test(s.accessToken) || !/^[-\w]{43}$/.test(s.refreshToken) || !Array.isArray(s.scopes)))
|
|
76
|
+
throw new AuthError('AUTH_CONFIG_INVALID'); return s; }
|
|
77
|
+
async putSecret(name, s) { await this.write(this.name(name) + '.secret.json', s); }
|
|
78
|
+
async lock(operation) {
|
|
79
|
+
await this.directory(true);
|
|
80
|
+
const file = path.join(this.root, 'operation.lock'), deadline = Date.now() + 20000;
|
|
81
|
+
let h;
|
|
82
|
+
while (!h) {
|
|
83
|
+
try {
|
|
84
|
+
h = await open(file, 'wx', 0o600);
|
|
85
|
+
await h.writeFile(JSON.stringify({ pid: process.pid, at: Date.now() }));
|
|
86
|
+
}
|
|
87
|
+
catch (e) {
|
|
88
|
+
if (h) {
|
|
89
|
+
await h.close();
|
|
90
|
+
h = undefined;
|
|
91
|
+
await unlink(file).catch(() => { });
|
|
92
|
+
throw e;
|
|
93
|
+
}
|
|
94
|
+
if (e.code !== 'EEXIST')
|
|
95
|
+
throw e;
|
|
96
|
+
let old;
|
|
97
|
+
try {
|
|
98
|
+
old = await this.read('operation.lock');
|
|
99
|
+
}
|
|
100
|
+
catch (e) {
|
|
101
|
+
if (!(e instanceof AuthError) || e.code !== 'AUTH_CONFIG_INVALID' || Date.now() >= deadline)
|
|
102
|
+
throw e;
|
|
103
|
+
await new Promise(r => setTimeout(r, 50));
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (old && Number.isSafeInteger(old.pid) && old.pid > 0 && Date.now() - old.at > 60000) {
|
|
107
|
+
let alive = true;
|
|
108
|
+
try {
|
|
109
|
+
process.kill(old.pid, 0);
|
|
110
|
+
}
|
|
111
|
+
catch (e) {
|
|
112
|
+
if (e.code === 'ESRCH')
|
|
113
|
+
alive = false;
|
|
114
|
+
}
|
|
115
|
+
if (!alive) {
|
|
116
|
+
await unlink(file).catch(() => { });
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
if (Date.now() >= deadline)
|
|
121
|
+
throw new AuthError('AUTH_CONFIG_BUSY');
|
|
122
|
+
await new Promise(r => setTimeout(r, 50));
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
try {
|
|
126
|
+
return await operation();
|
|
127
|
+
}
|
|
128
|
+
finally {
|
|
129
|
+
await h.close();
|
|
130
|
+
await unlink(file);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
async save(name, p, t) { this.name(name); return this.lock(async () => { const c = await this.config(), old = c.profiles[name]; if (old && ['issuer', 'resource', 'clientId', 'userId', 'tenantId', 'authorityVersion'].some(k => old.session[k] !== p.session[k]))
|
|
134
|
+
throw new AuthError('AUTH_CONTEXT_MISMATCH'); const previous = await this.secret(name); await this.putSecret(name, { ...t, generation: (previous?.generation ?? 0) + 1, state: 'READY' }); c.profiles[name] = p; c.selected = name; await this.write('profiles.json', c); }); }
|
|
135
|
+
async clear(name) { await this.directory(); await unlink(path.join(this.root, this.name(name) + '.secret.json')).catch(e => { if (e.code !== 'ENOENT')
|
|
136
|
+
throw e; }); }
|
|
137
|
+
async use(name) { return this.lock(async () => { const c = await this.config(); if (!Object.hasOwn(c.profiles, this.name(name)))
|
|
138
|
+
throw new AuthError('AUTH_PROFILE_INVALID'); c.selected = name; await this.write('profiles.json', c); return { selected: name }; }); }
|
|
139
|
+
async remove(name) { return this.lock(async () => { const c = await this.config(); if (await this.secret(name))
|
|
140
|
+
throw new AuthError('AUTH_LOGOUT_REQUIRED'); delete c.profiles[this.name(name)]; if (c.selected === name)
|
|
141
|
+
c.selected = null; await this.write('profiles.json', c); return { removed: name }; }); }
|
|
142
|
+
}
|
package/package.json
CHANGED
|
@@ -1,33 +1,29 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
2
|
+
"name": "@native-knowledge/cli",
|
|
3
|
+
"version": "0.1.0-rc.2",
|
|
3
4
|
"private": false,
|
|
4
5
|
"type": "module",
|
|
5
|
-
"
|
|
6
|
+
"description": "Remote Tenant CLI with OAuth and Agent-native discovery",
|
|
6
7
|
"engines": {
|
|
7
8
|
"node": ">=24"
|
|
8
9
|
},
|
|
10
|
+
"license": "Apache-2.0",
|
|
9
11
|
"repository": {
|
|
10
12
|
"type": "git",
|
|
11
13
|
"url": "git+https://github.com/SENLIN746/native-knowledge.git"
|
|
12
14
|
},
|
|
13
|
-
"publishConfig": {
|
|
14
|
-
"access": "public",
|
|
15
|
-
"tag": "next",
|
|
16
|
-
"registry": "https://registry.npmjs.org/"
|
|
17
|
-
},
|
|
18
15
|
"files": [
|
|
19
16
|
"dist",
|
|
20
17
|
"README.md",
|
|
21
|
-
"LICENSE"
|
|
18
|
+
"LICENSE",
|
|
19
|
+
"NOTICE"
|
|
22
20
|
],
|
|
23
|
-
"name": "@native-knowledge/cli",
|
|
24
|
-
"description": "Network CLI for native-knowledge",
|
|
25
21
|
"bin": {
|
|
26
22
|
"native-knowledge": "./dist/cli.js",
|
|
27
23
|
"knowledge-v2": "./dist/cli.js"
|
|
28
24
|
},
|
|
29
25
|
"dependencies": {
|
|
30
|
-
"@native-knowledge/knowledge-sdk": "0.1.0-rc.
|
|
31
|
-
"zod": "4.6.7"
|
|
26
|
+
"@native-knowledge/knowledge-sdk": "0.1.0-rc.2",
|
|
27
|
+
"zod": "^4.6.7"
|
|
32
28
|
}
|
|
33
|
-
}
|
|
29
|
+
}
|