@numa-tech/numa 1.20.3 → 1.20.5

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 (157) hide show
  1. package/README.md +24 -1
  2. package/dist/application-onboarding/schemas.d.ts +24 -0
  3. package/dist/application-onboarding/schemas.js +4 -0
  4. package/dist/application-onboarding/schemas.js.map +1 -1
  5. package/dist/application-onboarding/tui-model.d.ts +1 -0
  6. package/dist/application-onboarding/tui-model.js +10 -0
  7. package/dist/application-onboarding/tui-model.js.map +1 -1
  8. package/dist/application-onboarding/tui.js +1 -1
  9. package/dist/application-onboarding/tui.js.map +1 -1
  10. package/dist/authorization/application-client.d.ts +36 -1
  11. package/dist/authorization/application-client.js +4 -2
  12. package/dist/authorization/application-client.js.map +1 -1
  13. package/dist/authorization/application-commands.js +4 -3
  14. package/dist/authorization/application-commands.js.map +1 -1
  15. package/dist/authorization/application-schemas.d.ts +42 -7
  16. package/dist/authorization/application-schemas.js +19 -3
  17. package/dist/authorization/application-schemas.js.map +1 -1
  18. package/dist/business-issuer.js +8 -0
  19. package/dist/business-issuer.js.map +1 -1
  20. package/dist/cli.js +49 -31
  21. package/dist/cli.js.map +1 -1
  22. package/dist/command-catalog.js +18 -1
  23. package/dist/command-catalog.js.map +1 -1
  24. package/dist/kb/catalog.d.ts +2 -0
  25. package/dist/kb/catalog.js +14 -0
  26. package/dist/kb/catalog.js.map +1 -0
  27. package/dist/kb/client.d.ts +46 -0
  28. package/dist/kb/client.js +272 -0
  29. package/dist/kb/client.js.map +1 -0
  30. package/dist/kb/commands.d.ts +14 -0
  31. package/dist/kb/commands.js +121 -0
  32. package/dist/kb/commands.js.map +1 -0
  33. package/dist/kb/config.d.ts +15 -0
  34. package/dist/kb/config.js +76 -0
  35. package/dist/kb/config.js.map +1 -0
  36. package/dist/kb/errors.d.ts +9 -0
  37. package/dist/kb/errors.js +31 -0
  38. package/dist/kb/errors.js.map +1 -0
  39. package/dist/kb/transfers.d.ts +67 -0
  40. package/dist/kb/transfers.js +257 -0
  41. package/dist/kb/transfers.js.map +1 -0
  42. package/dist/kb/types.d.ts +81 -0
  43. package/dist/kb/types.js +2 -0
  44. package/dist/kb/types.js.map +1 -0
  45. package/dist/kb/upload-state.d.ts +20 -0
  46. package/dist/kb/upload-state.js +135 -0
  47. package/dist/kb/upload-state.js.map +1 -0
  48. package/dist/login-recovery.js +15 -1
  49. package/dist/login-recovery.js.map +1 -1
  50. package/dist/maintenance/modules.js +1 -1
  51. package/dist/maintenance/modules.js.map +1 -1
  52. package/dist/mcp/catalog.js +9 -1
  53. package/dist/mcp/catalog.js.map +1 -1
  54. package/dist/oss/commands.js +20 -0
  55. package/dist/oss/commands.js.map +1 -1
  56. package/dist/oss/download-links.d.ts +28 -0
  57. package/dist/oss/download-links.js +124 -0
  58. package/dist/oss/download-links.js.map +1 -0
  59. package/dist/oss/errors.js +1 -1
  60. package/dist/oss/errors.js.map +1 -1
  61. package/dist/oss/schemas.d.ts +15 -0
  62. package/dist/oss/schemas.js +2 -0
  63. package/dist/oss/schemas.js.map +1 -1
  64. package/dist/oss/signed-url-transfers.d.ts +41 -0
  65. package/dist/oss/signed-url-transfers.js +207 -0
  66. package/dist/oss/signed-url-transfers.js.map +1 -0
  67. package/dist/oss/tools.js +18 -0
  68. package/dist/oss/tools.js.map +1 -1
  69. package/dist/oss/transfer-pool.d.ts +2 -0
  70. package/dist/oss/transfer-pool.js +27 -0
  71. package/dist/oss/transfer-pool.js.map +1 -0
  72. package/dist/oss/transfer-worker.js +8 -17
  73. package/dist/oss/transfer-worker.js.map +1 -1
  74. package/dist/oss/transfers.d.ts +2 -0
  75. package/dist/oss/transfers.js +27 -0
  76. package/dist/oss/transfers.js.map +1 -1
  77. package/dist/oss/web-page.js +60 -5
  78. package/dist/oss/web-page.js.map +1 -1
  79. package/dist/oss/web.js +26 -0
  80. package/dist/oss/web.js.map +1 -1
  81. package/dist/platform-profile.d.ts +1 -1
  82. package/dist/server.d.ts +2 -0
  83. package/dist/server.js +2 -0
  84. package/dist/server.js.map +1 -1
  85. package/dist/tasks/commands.d.ts +9 -0
  86. package/dist/tasks/commands.js +60 -0
  87. package/dist/tasks/commands.js.map +1 -0
  88. package/dist/tasks/oss-query.d.ts +56 -0
  89. package/dist/tasks/oss-query.js +176 -0
  90. package/dist/tasks/oss-query.js.map +1 -0
  91. package/dist/tasks/runtime.d.ts +151 -0
  92. package/dist/tasks/runtime.js +71 -0
  93. package/dist/tasks/runtime.js.map +1 -0
  94. package/dist/tasks/tools.d.ts +3 -0
  95. package/dist/tasks/tools.js +16 -0
  96. package/dist/tasks/tools.js.map +1 -0
  97. package/dist/tasks/types.d.ts +14 -0
  98. package/dist/tasks/types.js +4 -0
  99. package/dist/tasks/types.js.map +1 -0
  100. package/dist/tasks/wecom-notify.d.ts +26 -0
  101. package/dist/tasks/wecom-notify.js +150 -0
  102. package/dist/tasks/wecom-notify.js.map +1 -0
  103. package/docs/agent-tasks.md +103 -0
  104. package/docs/application-default-groups.md +10 -2
  105. package/docs/design/kb-cli.md +94 -0
  106. package/docs/kb-access.md +85 -0
  107. package/package.json +13 -7
  108. package/scripts/export-kb-contract.py +158 -0
  109. package/skills/numa-ai-registry/SKILL.md +2 -2
  110. package/skills/numa-cli/SKILL.md +24 -9
  111. package/skills/numa-cli/agents/openai.yaml +2 -2
  112. package/skills/numa-cli/evals/evals.json +13 -1
  113. package/skills/numa-cli/numa-skill.json +1 -1
  114. package/skills/numa-cli/references/cli-bootstrap.md +8 -8
  115. package/skills/numa-cli/references/cli-mcp.md +28 -20
  116. package/skills/numa-cli/references/pipeline-release.md +9 -9
  117. package/skills/numa-cli/references/skills-command-contract.md +40 -40
  118. package/skills/numa-cli/references/skills-updates.md +13 -13
  119. package/skills/numa-cli/references/skills-workflows.md +4 -4
  120. package/skills/numa-create-application/SKILL.md +1 -1
  121. package/skills/numa-create-application/numa-skill.json +2 -2
  122. package/skills/numa-create-application/references/cli-bootstrap.md +3 -3
  123. package/skills/numa-create-application/references/numa-cli.md +16 -16
  124. package/skills/numa-jenkins-deployment/SKILL.md +8 -8
  125. package/skills/numa-jenkins-deployment/numa-skill.json +2 -2
  126. package/skills/numa-jenkins-deployment/references/cli-bootstrap.md +3 -3
  127. package/skills/numa-jenkins-deployment/references/cli-contract.md +7 -7
  128. package/skills/numa-jenkins-deployment/references/diagnostics.md +2 -2
  129. package/skills/numa-local-flux-deploy/SKILL.md +1 -1
  130. package/skills/numa-local-flux-deploy/numa-skill.json +2 -2
  131. package/skills/numa-local-flux-deploy/references/cli-bootstrap.md +3 -3
  132. package/skills/numa-nacos/SKILL.md +4 -4
  133. package/skills/numa-nacos/numa-skill.json +2 -2
  134. package/skills/numa-nacos/references/cli-bootstrap.md +3 -3
  135. package/skills/numa-nacos/references/command-contract.md +17 -17
  136. package/skills/numa-notion/SKILL.md +4 -4
  137. package/skills/numa-notion/numa-skill.json +2 -2
  138. package/skills/numa-notion/references/agents-automation.md +2 -2
  139. package/skills/numa-notion/references/cli-bootstrap.md +3 -3
  140. package/skills/numa-notion/references/cli.md +17 -17
  141. package/skills/numa-oss-access/SKILL.md +35 -77
  142. package/skills/numa-oss-access/agents/openai.yaml +2 -2
  143. package/skills/numa-oss-access/evals/evals.json +48 -0
  144. package/skills/numa-oss-access/numa-skill.json +2 -2
  145. package/skills/numa-oss-access/references/cli-bootstrap.md +5 -5
  146. package/skills/numa-oss-access/references/download-links.md +42 -0
  147. package/skills/numa-oss-access/references/object-operations.md +95 -0
  148. package/skills/numa-oss-access/references/search-and-mcp.md +17 -11
  149. package/skills/numa-wecom/SKILL.md +27 -62
  150. package/skills/numa-wecom/agents/openai.yaml +2 -2
  151. package/skills/numa-wecom/evals/evals.json +25 -0
  152. package/skills/numa-wecom/numa-skill.json +2 -2
  153. package/skills/numa-wecom/references/cli-bootstrap.md +5 -5
  154. package/skills/numa-wecom/references/legacy-operations.md +71 -0
  155. package/skills/numa-wecom/references/machine-auth.md +7 -7
  156. package/skills/numa-wecom/references/mcp.md +9 -8
  157. package/src/kb/openapi-contract.json +1432 -0
@@ -0,0 +1,151 @@
1
+ import { z } from "zod";
2
+ import { type AuthConfig } from "../config.js";
3
+ import { type WecomNotifyDependencies } from "./wecom-notify.js";
4
+ import { type OssQueryDependencies } from "./oss-query.js";
5
+ import type { TaskResult } from "./types.js";
6
+ export declare const TASKS: readonly [{
7
+ readonly name: "wecom.notify";
8
+ readonly tool: "numa_wecom_notify";
9
+ readonly module: "wecom";
10
+ readonly readOnly: false;
11
+ readonly description: "一次完成企微通道检查、精确收件人解析、已授权通知发送和未知结果查询。";
12
+ readonly schema: z.ZodObject<{
13
+ recipient_email: z.ZodOptional<z.ZodString>;
14
+ email_type: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<2>]>>;
15
+ recipient_user_ids: z.ZodOptional<z.ZodArray<z.ZodString>>;
16
+ content: z.ZodOptional<z.ZodString>;
17
+ message_type: z.ZodDefault<z.ZodEnum<{
18
+ markdown: "markdown";
19
+ text: "text";
20
+ }>>;
21
+ safe: z.ZodDefault<z.ZodBoolean>;
22
+ request_id: z.ZodOptional<z.ZodString>;
23
+ confirmed: z.ZodDefault<z.ZodBoolean>;
24
+ }, z.core.$strict>;
25
+ }, {
26
+ readonly name: "oss.query";
27
+ readonly tool: "numa_oss_query";
28
+ readonly module: "oss";
29
+ readonly readOnly: true;
30
+ readonly description: "按五级访问优先级选择 Grant 并有界检索 OSS;每次会话均核对精确目标。";
31
+ readonly schema: z.ZodObject<{
32
+ grant_id: z.ZodOptional<z.ZodNumber>;
33
+ bucket: z.ZodOptional<z.ZodString>;
34
+ prefix: z.ZodOptional<z.ZodString>;
35
+ ttl: z.ZodOptional<z.ZodNumber>;
36
+ marker: z.ZodOptional<z.ZodString>;
37
+ delimiter: z.ZodOptional<z.ZodLiteral<"/">>;
38
+ directories_only: z.ZodOptional<z.ZodBoolean>;
39
+ contains: z.ZodOptional<z.ZodString>;
40
+ suffix: z.ZodOptional<z.ZodString>;
41
+ ignore_case: z.ZodOptional<z.ZodBoolean>;
42
+ min_size: z.ZodOptional<z.ZodNumber>;
43
+ max_size: z.ZodOptional<z.ZodNumber>;
44
+ modified_after: z.ZodOptional<z.ZodString>;
45
+ modified_before: z.ZodOptional<z.ZodString>;
46
+ created_time_key: z.ZodOptional<z.ZodString>;
47
+ created_after: z.ZodOptional<z.ZodString>;
48
+ created_before: z.ZodOptional<z.ZodString>;
49
+ meta: z.ZodOptional<z.ZodArray<z.ZodString>>;
50
+ content_type: z.ZodOptional<z.ZodString>;
51
+ sort: z.ZodDefault<z.ZodEnum<{
52
+ created: "created";
53
+ key: "key";
54
+ modified: "modified";
55
+ size: "size";
56
+ }>>;
57
+ order: z.ZodDefault<z.ZodEnum<{
58
+ asc: "asc";
59
+ desc: "desc";
60
+ }>>;
61
+ limit: z.ZodDefault<z.ZodNumber>;
62
+ scan_limit: z.ZodDefault<z.ZodNumber>;
63
+ fields: z.ZodOptional<z.ZodArray<z.ZodEnum<{
64
+ contentType: "contentType";
65
+ createdAt: "createdAt";
66
+ etag: "etag";
67
+ key: "key";
68
+ kind: "kind";
69
+ lastModified: "lastModified";
70
+ metadata: "metadata";
71
+ sizeBytes: "sizeBytes";
72
+ storageClass: "storageClass";
73
+ type: "type";
74
+ }>>>;
75
+ }, z.core.$strict>;
76
+ }];
77
+ export interface TaskDependencies {
78
+ wecom?: WecomNotifyDependencies;
79
+ oss?: OssQueryDependencies;
80
+ /** Injection points keep tests offline; production always validates the selected profile. */
81
+ initializeProfile?: () => Promise<void>;
82
+ config?: (task: string) => AuthConfig;
83
+ }
84
+ export declare function inspectTasks(name?: string): {
85
+ name: "oss.query" | "wecom.notify";
86
+ tool: "numa_oss_query" | "numa_wecom_notify";
87
+ module: "oss" | "wecom";
88
+ description: "一次完成企微通道检查、精确收件人解析、已授权通知发送和未知结果查询。" | "按五级访问优先级选择 Grant 并有界检索 OSS;每次会话均核对精确目标。";
89
+ read_only: boolean;
90
+ input_schema: z.core.ZodStandardJSONSchemaPayload<z.ZodObject<{
91
+ recipient_email: z.ZodOptional<z.ZodString>;
92
+ email_type: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<2>]>>;
93
+ recipient_user_ids: z.ZodOptional<z.ZodArray<z.ZodString>>;
94
+ content: z.ZodOptional<z.ZodString>;
95
+ message_type: z.ZodDefault<z.ZodEnum<{
96
+ markdown: "markdown";
97
+ text: "text";
98
+ }>>;
99
+ safe: z.ZodDefault<z.ZodBoolean>;
100
+ request_id: z.ZodOptional<z.ZodString>;
101
+ confirmed: z.ZodDefault<z.ZodBoolean>;
102
+ }, z.core.$strict> | z.ZodObject<{
103
+ grant_id: z.ZodOptional<z.ZodNumber>;
104
+ bucket: z.ZodOptional<z.ZodString>;
105
+ prefix: z.ZodOptional<z.ZodString>;
106
+ ttl: z.ZodOptional<z.ZodNumber>;
107
+ marker: z.ZodOptional<z.ZodString>;
108
+ delimiter: z.ZodOptional<z.ZodLiteral<"/">>;
109
+ directories_only: z.ZodOptional<z.ZodBoolean>;
110
+ contains: z.ZodOptional<z.ZodString>;
111
+ suffix: z.ZodOptional<z.ZodString>;
112
+ ignore_case: z.ZodOptional<z.ZodBoolean>;
113
+ min_size: z.ZodOptional<z.ZodNumber>;
114
+ max_size: z.ZodOptional<z.ZodNumber>;
115
+ modified_after: z.ZodOptional<z.ZodString>;
116
+ modified_before: z.ZodOptional<z.ZodString>;
117
+ created_time_key: z.ZodOptional<z.ZodString>;
118
+ created_after: z.ZodOptional<z.ZodString>;
119
+ created_before: z.ZodOptional<z.ZodString>;
120
+ meta: z.ZodOptional<z.ZodArray<z.ZodString>>;
121
+ content_type: z.ZodOptional<z.ZodString>;
122
+ sort: z.ZodDefault<z.ZodEnum<{
123
+ created: "created";
124
+ key: "key";
125
+ modified: "modified";
126
+ size: "size";
127
+ }>>;
128
+ order: z.ZodDefault<z.ZodEnum<{
129
+ asc: "asc";
130
+ desc: "desc";
131
+ }>>;
132
+ limit: z.ZodDefault<z.ZodNumber>;
133
+ scan_limit: z.ZodDefault<z.ZodNumber>;
134
+ fields: z.ZodOptional<z.ZodArray<z.ZodEnum<{
135
+ contentType: "contentType";
136
+ createdAt: "createdAt";
137
+ etag: "etag";
138
+ key: "key";
139
+ kind: "kind";
140
+ lastModified: "lastModified";
141
+ metadata: "metadata";
142
+ sizeBytes: "sizeBytes";
143
+ storageClass: "storageClass";
144
+ type: "type";
145
+ }>>>;
146
+ }, z.core.$strict>>;
147
+ result_statuses: string[];
148
+ }[];
149
+ /** Validate configuration only. Clients obtain/reuse tokens and the server enforces authorization. */
150
+ export declare function validateTaskIdentity(config: AuthConfig): void;
151
+ export declare function runTask(name: string, input: unknown, dependencies?: TaskDependencies): Promise<TaskResult>;
@@ -0,0 +1,71 @@
1
+ import { z } from "zod";
2
+ import { loadConfig } from "../config.js";
3
+ import { currentPlatformProfile, initializePlatformProfile } from "../platform-profile.js";
4
+ import { runWecomNotify, wecomNotifySchema } from "./wecom-notify.js";
5
+ import { runOssQuery, ossQuerySchema } from "./oss-query.js";
6
+ export const TASKS = [
7
+ { name: "wecom.notify", tool: "numa_wecom_notify", module: "wecom", readOnly: false,
8
+ description: "一次完成企微通道检查、精确收件人解析、已授权通知发送和未知结果查询。", schema: wecomNotifySchema },
9
+ { name: "oss.query", tool: "numa_oss_query", module: "oss", readOnly: true,
10
+ description: "按五级访问优先级选择 Grant 并有界检索 OSS;每次会话均核对精确目标。", schema: ossQuerySchema },
11
+ ];
12
+ export function inspectTasks(name) {
13
+ return TASKS.filter(task => name === undefined || task.name === name).map(task => ({
14
+ name: task.name, tool: task.tool, module: task.module,
15
+ description: task.description, read_only: task.readOnly,
16
+ input_schema: z.toJSONSchema(task.schema, { io: "input" }),
17
+ result_statuses: ["succeeded", "needs_input", "blocked", "pending"],
18
+ }));
19
+ }
20
+ /** Validate configuration only. Clients obtain/reuse tokens and the server enforces authorization. */
21
+ export function validateTaskIdentity(config) {
22
+ if (!config.backendBaseUrl || !config.discoveryUrl || !config.clientId?.trim())
23
+ throw Object.assign(new Error(), { code: "TASK_CONFIGURATION_REQUIRED" });
24
+ if (config.authenticationMode === "client_credentials") {
25
+ if (config.clientId === "mcp-client" || Boolean(config.clientSecret) === Boolean(config.clientSecretFile))
26
+ throw Object.assign(new Error(), { code: "TASK_MACHINE_IDENTITY_REQUIRED" });
27
+ }
28
+ else if (config.clientSecret || config.clientSecretFile) {
29
+ // An explicit browser identity must not accidentally consume machine credentials.
30
+ throw Object.assign(new Error(), { code: "TASK_IDENTITY_CONFLICT" });
31
+ }
32
+ }
33
+ const configurationMessages = {
34
+ TASK_CONFIGURATION_REQUIRED: "Configure the selected platform API, issuer and client before running this task.",
35
+ TASK_MACHINE_IDENTITY_REQUIRED: "Machine mode requires a dedicated client and exactly one Secret source in this process environment. No browser fallback was attempted.",
36
+ TASK_IDENTITY_CONFLICT: "Browser mode and machine credentials conflict. Correct this process configuration; identity was not changed.",
37
+ };
38
+ export async function runTask(name, input, dependencies = {}) {
39
+ const task = TASKS.find(item => item.name === name);
40
+ if (!task)
41
+ return { task: name, status: "blocked", error: { code: "TASK_UNKNOWN", message: "Unknown task. Use task inspect to list supported tasks." } };
42
+ // Validate shape before loading a profile, obtaining credentials, or making any network requests.
43
+ const parsed = task.schema.safeParse(input);
44
+ if (!parsed.success)
45
+ return { task: name, status: "needs_input",
46
+ missing: [...new Set(parsed.error.issues.map(issue => issue.path.join(".") || "input"))],
47
+ error: { code: "TASK_INPUT_INVALID", message: "Task input does not match its schema. Correct the listed fields." } };
48
+ try {
49
+ const beforeExecute = async () => {
50
+ if (dependencies.initializeProfile)
51
+ await dependencies.initializeProfile();
52
+ else if (!currentPlatformProfile())
53
+ await initializePlatformProfile();
54
+ const config = dependencies.config?.(name) ?? loadConfig(name === "oss.query" ? "oss" : "platform");
55
+ validateTaskIdentity(config);
56
+ };
57
+ const result = name === "wecom.notify"
58
+ ? await runWecomNotify(parsed.data, { ...dependencies.wecom, beforeExecute })
59
+ : await runOssQuery(parsed.data, { ...dependencies.oss, beforeExecute });
60
+ // Each task owns output projection/redaction. Do not rewrite opaque recovery IDs here.
61
+ return result;
62
+ }
63
+ catch (error) {
64
+ // Never expose provider exceptions, request objects, credentials, or arbitrary response bodies.
65
+ const rawCode = error && typeof error === "object" && "code" in error ? error.code : undefined;
66
+ const code = typeof rawCode === "string" && /^[A-Za-z][A-Za-z0-9_]{0,79}$/u.test(rawCode) ? rawCode : "TASK_CONFIGURATION_OR_AUTH_FAILED";
67
+ return { task: name, status: "blocked", error: { code,
68
+ message: configurationMessages[code] ?? "Task initialization failed. Check the selected profile and process authentication configuration; no alternate identity was used." } };
69
+ }
70
+ }
71
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/tasks/runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { type TaskDependencies } from "./runtime.js";
3
+ export declare function registerTaskTools(server: McpServer, modules: ReadonlySet<string>, dependencies?: TaskDependencies): void;
@@ -0,0 +1,16 @@
1
+ import { TASKS, runTask } from "./runtime.js";
2
+ export function registerTaskTools(server, modules, dependencies = {}) {
3
+ for (const task of TASKS) {
4
+ if (!modules.has(task.module))
5
+ continue;
6
+ server.registerTool(task.tool, {
7
+ description: `${task.description} Call this task directly; configuration/authentication and required lookups run internally, without separate auth/catalog/capability calls. Uses this MCP process identity and environment. Returns succeeded, needs_input, blocked or pending. ${task.readOnly ? "Read-only bounded query; automatic Grants are tried by accessPriority (HIGHEST, HIGH, NORMAL, LOW, LOWEST), then grant ID. Fresh sessions must cover the exact target. Explicit grant_id never falls back. If data.priority_advice is present, report the successful result and the matching Grant IDs/priorities, then ask whether the user wants to adjust priorities for future access. not_tested Grants are metadata matches, not verified access. Never change priorities without the user's choice." : "SIDE EFFECT: requires user-approved exact recipients and content, confirmed=true and a stable request_id. ACCEPTED is not delivery. pending must be recovered with numa_wecom_status using the same request_id; never resend."}`,
8
+ inputSchema: task.schema,
9
+ annotations: { readOnlyHint: task.readOnly, destructiveHint: false, idempotentHint: task.readOnly, openWorldHint: true },
10
+ }, async (input) => {
11
+ const result = await runTask(task.name, input, dependencies);
12
+ return { isError: result.status === "blocked", content: [{ type: "text", text: JSON.stringify(result) }], structuredContent: { ...result } };
13
+ });
14
+ }
15
+ }
16
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","sourceRoot":"","sources":["../../src/tasks/tools.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAyB,MAAM,cAAc,CAAC;AAErE,MAAM,UAAU,iBAAiB,CAAC,MAAiB,EAAE,OAA4B,EAAE,YAAY,GAAqB,EAAE;IACpH,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC;YAAE,SAAS;QACxC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE;YAC7B,WAAW,EAAE,GAAG,IAAI,CAAC,WAAW,mPAAmP,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,4eAA4e,CAAC,CAAC,CAAC,+NAA+N,EAAE;YACn/B,WAAW,EAAE,IAAI,CAAC,MAAM;YACxB,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,QAAQ,EAAE,eAAe,EAAE,KAAK,EAAE,cAAc,EAAE,IAAI,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE;SACzH,EAAE,KAAK,EAAE,KAAc,EAAE,EAAE;YAC1B,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE,YAAY,CAAC,CAAC;YAC7D,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,KAAK,SAAS,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC,EAAE,iBAAiB,EAAE,EAAE,GAAG,MAAM,EAAE,EAAE,CAAC;QACxJ,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ /** A task result is actionable without another discovery/preflight model turn. */
2
+ export interface TaskResult {
3
+ status: "succeeded" | "needs_input" | "blocked" | "pending";
4
+ task: string;
5
+ data?: unknown;
6
+ error?: {
7
+ code: string;
8
+ message: string;
9
+ };
10
+ missing?: string[];
11
+ candidates?: unknown[];
12
+ request_id?: string;
13
+ }
14
+ export declare function taskExitCode(result: TaskResult): number;
@@ -0,0 +1,4 @@
1
+ export function taskExitCode(result) {
2
+ return { succeeded: 0, needs_input: 2, blocked: 3, pending: 4 }[result.status];
3
+ }
4
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/tasks/types.ts"],"names":[],"mappings":"AAWA,MAAM,UAAU,YAAY,CAAC,MAAkB;IAC7C,OAAO,EAAE,SAAS,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;AACjF,CAAC"}
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ import { WecomClient } from "../wecom/client.js";
3
+ import type { TaskResult } from "./types.js";
4
+ /** Optional fields let both entry points return actionable needs_input results. */
5
+ export declare const wecomNotifySchema: z.ZodObject<{
6
+ recipient_email: z.ZodOptional<z.ZodString>;
7
+ email_type: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<1>, z.ZodLiteral<2>]>>;
8
+ recipient_user_ids: z.ZodOptional<z.ZodArray<z.ZodString>>;
9
+ content: z.ZodOptional<z.ZodString>;
10
+ message_type: z.ZodDefault<z.ZodEnum<{
11
+ markdown: "markdown";
12
+ text: "text";
13
+ }>>;
14
+ safe: z.ZodDefault<z.ZodBoolean>;
15
+ request_id: z.ZodOptional<z.ZodString>;
16
+ confirmed: z.ZodDefault<z.ZodBoolean>;
17
+ }, z.core.$strict>;
18
+ type NotifyClient = Pick<WecomClient, "capabilities" | "recipientByEmail" | "send" | "statusByRequest">;
19
+ export interface WecomNotifyDependencies {
20
+ client?: NotifyClient;
21
+ clientFactory?: () => NotifyClient;
22
+ beforeExecute?: () => Promise<void>;
23
+ }
24
+ /** Deterministic, bounded notification workflow shared by CLI and MCP. */
25
+ export declare function runWecomNotify(input: unknown, dependencies?: WecomNotifyDependencies): Promise<TaskResult>;
26
+ export {};
@@ -0,0 +1,150 @@
1
+ import { z } from "zod";
2
+ import { loadConfig } from "../config.js";
3
+ import { WecomClient } from "../wecom/client.js";
4
+ import { WecomError } from "../wecom/errors.js";
5
+ import { EmailSchema, EmailTypeSchema, MessageTypeSchema, RequestIdSchema, SendMessageSchema, UserIdSchema } from "../wecom/schemas.js";
6
+ /** Optional fields let both entry points return actionable needs_input results. */
7
+ export const wecomNotifySchema = z.object({
8
+ recipient_email: EmailSchema.optional(),
9
+ email_type: EmailTypeSchema.optional(),
10
+ recipient_user_ids: z.array(UserIdSchema).min(1).max(100).refine(ids => new Set(ids).size === ids.length).optional(),
11
+ content: z.string().min(1).refine(value => value.trim().length > 0).optional(),
12
+ message_type: MessageTypeSchema.default("text"),
13
+ safe: z.boolean().default(false),
14
+ request_id: RequestIdSchema.optional(),
15
+ confirmed: z.boolean().default(false).describe("True only when the user has authorized these exact recipients and content; existing authorization is sufficient")
16
+ }).strict();
17
+ const task = "wecom.notify";
18
+ function blocked(code, message, requestId) {
19
+ return { task, status: "blocked", error: { code, message }, ...(requestId ? { request_id: requestId } : {}) };
20
+ }
21
+ function pending(requestId) {
22
+ return { task, status: "pending", request_id: requestId, error: {
23
+ code: "WECOM_RESULT_PENDING",
24
+ message: "Send acceptance is not yet known. Query status using this request_id; do not resend or generate a new request ID."
25
+ } };
26
+ }
27
+ function safeError(error, requestId) {
28
+ const status = error instanceof WecomError ? error.status : undefined;
29
+ return blocked(status === 401 ? "WECOM_AUTHENTICATION_REQUIRED" : status === 403 ? "WECOM_PERMISSION_DENIED" : "WECOM_TASK_BLOCKED", status === 401 || status === 403
30
+ ? "The configured identity cannot complete this operation. Correct its authentication or grants; do not switch identities."
31
+ : "WeCom operation failed before acceptance. Check channel configuration, exact recipient and email type, and the configured identity. No automatic retry was made.", requestId);
32
+ }
33
+ function receiptResult(receipt, requestId) {
34
+ // Never report another request's receipt as acceptance of this one.
35
+ if (receipt.requestId !== requestId)
36
+ return pending(requestId);
37
+ const data = { message_id: receipt.id, receipt_status: receipt.status,
38
+ recipient_user_ids: receipt.recipientUserIds, invalid_user_ids: receipt.invalidUserIds };
39
+ if (receipt.status === "ACCEPTED")
40
+ return { task, status: "succeeded", request_id: requestId,
41
+ data: { ...data, message: "Accepted by the WeCom API; delivery and read status are not confirmed." } };
42
+ if (receipt.status === "SENDING" || receipt.status === "UNKNOWN")
43
+ return { ...pending(requestId), data };
44
+ return { ...blocked(receipt.status === "PARTIAL" ? "WECOM_PARTIAL_ACCEPTANCE" : "WECOM_SEND_FAILED", receipt.status === "PARTIAL"
45
+ ? "The API accepted only some recipients. Review the receipt; do not resend to the full recipient list."
46
+ : "The API reported a failed send. Review the receipt before taking further action.", requestId), data };
47
+ }
48
+ async function recover(client, requestId) {
49
+ try {
50
+ return receiptResult(await client.statusByRequest(requestId), requestId);
51
+ }
52
+ catch (error) {
53
+ if (error instanceof WecomError && (error.status === 401 || error.status === 403)) {
54
+ return { ...safeError(error, requestId), data: { send_outcome: "unknown", message: "The send outcome remains unknown. Restore access and query this request_id; do not resend." } };
55
+ }
56
+ // A missing ledger entry, unavailable platform, or invalid receipt is not proof of no send.
57
+ return pending(requestId);
58
+ }
59
+ }
60
+ /** Deterministic, bounded notification workflow shared by CLI and MCP. */
61
+ export async function runWecomNotify(input, dependencies = {}) {
62
+ const parsed = wecomNotifySchema.safeParse(input);
63
+ if (!parsed.success)
64
+ return { task, status: "needs_input", missing: [...new Set(parsed.error.issues
65
+ .map(issue => typeof issue.path[0] === "string" ? issue.path[0] : "input"))],
66
+ error: { code: "WECOM_INPUT_INVALID", message: "Supply valid notification fields, exact recipients, and a stable request_id of 8-128 safe ASCII characters." } };
67
+ const value = parsed.data;
68
+ const missing = [];
69
+ if (!value.content)
70
+ missing.push("content");
71
+ if (!value.request_id)
72
+ missing.push("request_id");
73
+ if (!value.confirmed)
74
+ missing.push("confirmed");
75
+ if (!value.recipient_email && !value.recipient_user_ids)
76
+ missing.push("recipient_email or recipient_user_ids");
77
+ if (value.recipient_email && value.email_type === undefined)
78
+ missing.push("email_type");
79
+ if (missing.length)
80
+ return { task, status: "needs_input", missing, error: { code: "WECOM_INPUT_REQUIRED",
81
+ message: "Provide the missing fields. confirmed=true represents existing user authorization for these exact recipients and content; ask only if authorization is absent." } };
82
+ const requestId = value.request_id;
83
+ const body = SendMessageSchema.safeParse({
84
+ ...(value.recipient_email ? { recipientEmail: value.recipient_email, emailType: value.email_type } : {}),
85
+ ...(value.recipient_user_ids ? { recipientUserIds: value.recipient_user_ids } : {}),
86
+ // An email_type without email is invalid even when userid recipients were supplied.
87
+ ...(!value.recipient_email && value.email_type !== undefined ? { emailType: value.email_type } : {}),
88
+ messageType: value.message_type, content: value.content, safe: value.safe
89
+ });
90
+ if (!body.success) {
91
+ const names = { recipientUserIds: "recipient_user_ids", recipientEmail: "recipient_email", emailType: "email_type", messageType: "message_type" };
92
+ const fields = body.error.issues.map(issue => {
93
+ const field = typeof issue.path[0] === "string" ? issue.path[0] : "input";
94
+ // The shared DTO uses the recipientUserIds path for all recipient-mode conflicts.
95
+ if (field === "recipientUserIds" && value.email_type !== undefined && !value.recipient_email)
96
+ return "email_type";
97
+ return names[field] ?? field;
98
+ });
99
+ if (value.recipient_email && value.recipient_user_ids)
100
+ fields.push("recipient_email");
101
+ return { task, status: "needs_input", request_id: requestId, missing: [...new Set(fields)],
102
+ error: { code: "WECOM_INPUT_INVALID", message: "Choose exactly one recipient mode; content must fit 2048 UTF-8 bytes and safe mode is available only for text." } };
103
+ }
104
+ let client;
105
+ let recipientUserIds = value.recipient_user_ids;
106
+ // Shared runner preserves actionable authentication/configuration failures.
107
+ await dependencies.beforeExecute?.();
108
+ try {
109
+ client = dependencies.client ?? dependencies.clientFactory?.() ?? new WecomClient(loadConfig());
110
+ const caps = await client.capabilities();
111
+ if (!caps.enabled || !caps.configured)
112
+ return blocked("WECOM_CHANNEL_UNAVAILABLE", "The WeCom channel is disabled or not configured.", requestId);
113
+ if (!caps.messageTypes.includes(value.message_type))
114
+ return blocked("WECOM_MESSAGE_TYPE_UNSUPPORTED", "The channel does not support this message type.", requestId);
115
+ if ((recipientUserIds?.length ?? 1) > caps.maxRecipients)
116
+ return blocked("WECOM_RECIPIENT_LIMIT", "The requested recipients exceed the channel limit; reduce the explicit recipient list.", requestId);
117
+ const byteLimit = value.message_type === "text" ? caps.maxTextBytes : caps.maxMarkdownBytes;
118
+ if (Buffer.byteLength(value.content, "utf8") > byteLimit)
119
+ return blocked("WECOM_CONTENT_LIMIT", "The content exceeds the channel UTF-8 byte limit.", requestId);
120
+ if (value.recipient_email) {
121
+ const recipient = await client.recipientByEmail(value.recipient_email, value.email_type);
122
+ recipientUserIds = [recipient.userId];
123
+ }
124
+ }
125
+ catch (error) {
126
+ return safeError(error, requestId);
127
+ }
128
+ // Validate the resolved ID too: no mutation happens before the complete body is valid.
129
+ const resolved = SendMessageSchema.safeParse({ recipientUserIds, messageType: value.message_type, content: value.content, safe: value.safe });
130
+ if (!resolved.success)
131
+ return blocked("WECOM_RECIPIENT_INVALID", "The exact recipient could not be resolved to valid user IDs. Do not guess addresses or switch email types.", requestId);
132
+ try {
133
+ // Preserve mailbox + type in the POST: the server's idempotency fingerprint
134
+ // retains the original recipient resolution even if the mailbox later changes.
135
+ const receipt = await client.send(body.data, requestId);
136
+ if (receipt.requestId !== requestId || receipt.status === "UNKNOWN" || receipt.status === "SENDING")
137
+ return recover(client, requestId);
138
+ return receiptResult(receipt, requestId);
139
+ }
140
+ catch (error) {
141
+ if (error instanceof WecomError && error.code !== "WECOM_RESULT_UNKNOWN"
142
+ && (error.code === "WECOM_INPUT_INVALID" || error.status !== undefined && error.status >= 400 && error.status < 500))
143
+ return safeError(error, requestId);
144
+ if (error instanceof Error && error.name === "AuthError")
145
+ return safeError(error, requestId);
146
+ // Once POST was attempted, transport and unexpected errors are conservatively uncertain.
147
+ return recover(client, requestId);
148
+ }
149
+ }
150
+ //# sourceMappingURL=wecom-notify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wecom-notify.js","sourceRoot":"","sources":["../../src/tasks/wecom-notify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,103 @@
1
+ # Agent 业务任务入口
2
+
3
+ `task run` 将参数校验、当前进程身份配置检查和业务操作组合成一次调用。CLI 与 MCP 直接调用同一份任务函数;MCP 不启动 CLI 子进程。模型负责将用户意图转换成参数,缺项、歧义或执行失败时才继续判断。
4
+
5
+ 这是新增运行时能力。已安装的 Skill、CLI npm 版本、MCP 配置里固定的版本和已连接工具是不同状态;升级 Skill 不会更新运行时。安装/初始化时核对工具或 schema,正常任务无需再次逐项调用版本、help、auth status、whoami、config、capabilities 或 Grant 列表。
6
+
7
+ ## 入口与结果
8
+
9
+ | 任务 | MCP 工具 | 模块 |
10
+ | --- | --- | --- |
11
+ | `wecom.notify` | `numa_wecom_notify` | `wecom` |
12
+ | `oss.query` | `numa_oss_query` | `oss` |
13
+
14
+ ```sh
15
+ # 本地 schema 查询,无需登录或业务 API;省略名称可查看全部任务
16
+ numa task inspect wecom.notify --json
17
+ numa task inspect oss.query --json
18
+
19
+ # 业务调用;task.json 为 UTF-8 JSON 对象,最大 1 MiB
20
+ numa task run wecom.notify --input-file /ABS/notify.json --json
21
+ numa task run oss.query --input-file /ABS/query.json --json
22
+ # --input-file - 也可从 stdin 读取 JSON
23
+ ```
24
+
25
+ 运行结果是 JSON 对象,公共字段为 `task`、`status`;按结果可包含 `data`、`error:{code,message}`、`missing`、`candidates`、`request_id`。
26
+
27
+ | status | CLI 退出码 | 含义与后续动作 |
28
+ | --- | --- | --- |
29
+ | `succeeded` | 0 | 任务完成,解释业务结果与完整性限制 |
30
+ | `needs_input` | 2 | 输入缺失、无效或目标存在歧义,补齐字段或选择候选 |
31
+ | `blocked` | 3 | 配置、权限、范围或业务条件不满足,按脱敏错误处理 |
32
+ | `pending` | 4 | 发送结果尚未确定,保留请求号,仅查询回执 |
33
+
34
+ 进程中断、连接丢失或没有输出不能证明通知未发送。无论 CLI 退出码如何,已尝试的发送只能按原请求号恢复,不能自动重发。
35
+
36
+ ## 企微通知
37
+
38
+ 在用户已授权以下目标与内容的前提下,通知输入示例:
39
+
40
+ ```json
41
+ {
42
+ "recipient_email": "user@example.com",
43
+ "email_type": 2,
44
+ "message_type": "text",
45
+ "content": "构建已完成。",
46
+ "request_id": "notice-20260921-001",
47
+ "confirmed": true
48
+ }
49
+ ```
50
+
51
+ - 收件人模式二选一:精确 `recipient_email` + 显式 `email_type`,或精确 `recipient_user_ids` 数组。`email_type:1` 表示企微企业邮箱,`2` 表示成员资料邮箱,不能从邮箱域名猜测。
52
+ - `message_type` 默认 `text`,支持 `markdown`;`safe` 默认 `false`,Markdown 不支持 `safe:true`。
53
+ - `request_id` 是必需的 8–128 位稳定请求号,只使用字母、数字或 `._:-`。发送前保存,同一意图不换号。
54
+ - `confirmed:true` 表示用户已授权这次目标与正文。已明确授权时无需再问一次;它不是 dry-run。
55
+
56
+ 执行器在内部校验消息、能力与限额、按精确邮箱解析账号,并发送一次。未知结果最多查询一次回执,不自动再次发送。`succeeded` 中的 `data.receipt_status:ACCEPTED` 只表示企微 API 接受,不代表送达或已读;`PARTIAL` 为 `blocked` 并携带失败对象,不能重发全体。
57
+
58
+ `pending` 后调用 `numa_wecom_status` 或同一 CLI 的 `numa wecom status --request-id NOTICE_ID --json`,保持原身份。若恢复查询返回权限错误,仍可能已发送,先恢复原身份访问能力再查;不切换身份重新发送。平台 subject 模式、目录管理和映射维护继续使用低层工具,不属于此通知任务。
59
+
60
+ ## OSS 查询
61
+
62
+ 按精确 bucket/prefix 查询,由执行器按访问优先级选择启用且已同步、覆盖该范围的 Grant:
63
+
64
+ ```json
65
+ {
66
+ "bucket": "example-bucket",
67
+ "prefix": "reports/",
68
+ "suffix": ".pdf",
69
+ "sort": "modified",
70
+ "order": "desc",
71
+ "limit": 20,
72
+ "scan_limit": 1000,
73
+ "fields": ["key", "sizeBytes", "lastModified"]
74
+ }
75
+ ```
76
+
77
+ 也可直接传数值 `grant_id`;可选 `prefix` 限定查询,省略时沿用该 Grant 的授权范围。没有 `grant_id` 时必须提供 `bucket` 和 `prefix`;显式 `prefix:""` 表示请求 bucket 根目录。多个覆盖 Grant 按 `accessPriority` 顺序尝试:`HIGHEST`(最高)、`HIGH`(高)、`NORMAL`(普通,默认)、`LOW`(低)、`LOWEST`(最低);同级按 Grant ID 升序。列表中没有目标 bucket 时,按此顺序申请可用候选的新会话,核对返回的 bucket/prefix 后才读取对象;已知 bucket 的 prefix 不匹配时不扩大候选范围。显式指定 `grant_id` 不切换 Grant。候选超过 100 项返回 `needs_input` 和前 100 项候选,不申请会话。指定 Grant 的有效性和最终范围仍受平台与现有 OSS 客户端检查约束。
78
+
79
+ 筛选参数与 `numa_oss_search` 一致,包括目录、key/大小、修改时间、元数据、content-type、约定的创建时间字段、排序和输出列。`scan_limit` 默认 1000、最多 100000;`limit` 默认 100、最多 1000。需要元数据/创建时间时会对候选对象执行 HEAD,并要求 GetObject 权限。
80
+
81
+ 候选级 403/404/409/503、会话范围不匹配和操作权限不足可继续下一候选;认证失效(401)、无效响应和其他错误立即停止。成功空结果也结束尝试。自动查询的 `data.attempts` 记录先前失败候选的 Grant ID 与脱敏错误码,成功结果附带 `access_priority`。
82
+
83
+ 成功后仍有多个未失败的目标匹配 Grant 时,`data.priority_advice` 返回 `selected_grant_id`、`matching_grants` 和询问是否调整后续优先级的 `question`。匹配列表按优先级排序,只含公开目标/权限摘要,失败候选排除。`basis:grant_metadata` 表示配置匹配,`access_status:succeeded` 为本次使用的 Grant,其余为 `not_tested`,不能声称都已实际访问成功。此提示不增加平台/OSS 请求,不改变 `succeeded` 或现有结果。单一候选、显式 Grant 或只有不同 bucket 的回退候选不生成提示。
84
+
85
+ Agent 应先交付结果,再展示 Grant ID、优先级并询问是否调整。同一任务同一目标只提示一次,未回复不阻塞或修改配置。用户有意调整时明确 Grant 与级别,并引导平台授权编辑;查询工具自身不支持写入优先级。
86
+
87
+ 结果在 `data` 中包含搜索摘要与对象。`complete:false`、`truncated:true` 表示扫描未覆盖完整范围,`resultsLimited:true` 表示输出截断;排序只覆盖本次扫描。`nextMarker` 仅用于继续尚未扫描的对象,不能恢复当前 limit 截掉的匹配结果。`LastModified` 是修改时间,不能冒充创建时间;创建时间必须使用已有自定义元数据键。详见 [OSS 搜索与 MCP 契约](../skills/numa-oss-access/references/search-and-mcp.md)。
88
+
89
+ ## WorkBuddy 的身份与环境
90
+
91
+ `mcp.json` 的 `env` 传递给指定 MCP 服务启动进程:
92
+
93
+ ```text
94
+ WorkBuddy → npx → numa serve → 内部任务函数
95
+ ↑
96
+ mcp.json 的 env
97
+ ```
98
+
99
+ 机器模式由 `NUMA_KEYCLOAK_AUTH_MODE=client_credentials`、专用 `NUMA_KEYCLOAK_CLIENT_ID` 以及唯一 Secret 来源(`NUMA_KEYCLOAK_CLIENT_SECRET_FILE` 或 `NUMA_KEYCLOAK_CLIENT_SECRET`)提供。API/Issuer 遵循当前受治理的平台 profile,不通过随意覆盖环境变量切换平台。Secret 文件由认证库读取,Agent 无需读取正文。详情见 [MCP 安装](../skills/numa-cli/references/cli-mcp.md)。
100
+
101
+ 这些环境变量可供 `numa serve` 内部直接使用,不会自动反向导入 WorkBuddy 主进程或其他终端。业务 Skill 在初始化时选定 MCP 路径后保持使用它;缺少工具时报告版本或 `--modules`/`--tools` 配置问题,不自动改走终端、不复制 Secret、不回退个人登录。普通任务的身份检查内置于执行器,权限由实际业务请求的服务端检查。
102
+
103
+ 现有低层 CLI/MCP 工具仍可用于诊断、专门对象操作或用户明确选择的兼容流程。Skills 库上传、提交审核与发布仍是独立治理流程,任务入口不绕过两人制发布审核。
@@ -81,8 +81,11 @@ numa authorization application --app 1 identity client list --relation CALLERS -
81
81
  numa authorization application --app 2 identity client list --relation SERVICES --json
82
82
  ```
83
83
 
84
- Client 草稿可携带 `consumerApplicationIds` 声明调用方应用目录关系;这不会授予用户角色。
85
- 共享登录 Client 的 Audience 和角色范围仍在目标后端应用中保存,通过统一发布作业生效。
84
+ 应用分类使用 `applicationType: FRONTEND | BACKEND | FULLSTACK | UNCLASSIFIED`,可在 onboarding 的 application 配置中选择。仅渲染页面的 SSR 应用属于 FRONTEND,同时提供页面和业务 API 的应用属于 FULLSTACK;不根据框架或 Client 数量推断分类。
85
+
86
+ 调用方在本应用拥有的 Client 草稿中配置 `audienceTargets: [{ applicationId: 1, clientId: "backend-api" }]`,精确指定目标后端应用及应用 Client。一个应用可有多个应用 Client,Audience 只由调用方修改;`CALLERS` 是被调用方的只读反查。旧 `consumerApplicationIds` 和 `demand.audience` 写字段已移除。Audience 不授予角色,角色授予仍需独立配置,变更统一通过“环境与发布”生效。
87
+
88
+ API 资源通过 `resources[].clientId` 声明资源所属应用 Client,角色通过 `roles[].clientId` 声明所属 Client。同名角色必须按所属 Client 区分;`defaultRoleClientId` 只作为未显式指定时的默认值。PAGE 不配置资源 Client。
86
89
 
87
90
  PAGE 草稿可以引用其他应用的固定功能版本,格式为
88
91
  `permissionSource: { applicationId, definitionVersion, functionCode }` 与 `actions`。
@@ -99,3 +102,8 @@ numa authorization application --app 1 definition page-transfer apply --file rev
99
102
 
100
103
  迁移只更新平台草稿,历史版本和线上配置不变。固定前端版本并通过“环境与发布”发布后,页面规则才生效。
101
104
  后端权限版本升级后,应相应更新前端的固定版本引用再发布。CLI 需要配合提供 PAGE 与迁移接口的后端版本使用。
105
+
106
+
107
+ 多 Client 的角色关系写入使用 `ownerClientId` 和裸 `roleName` 明确角色归属;`clientInstanceId` 始终表示接收角色的服务账号所属 Client 实例。省略 owner 只在应用拥有唯一候选 Client 时可解析,歧义会阻断。查询指定 Client 的已发布角色证据可用 `identity subject-access <subject> --env <uuid> --owner-client <client-id>`。
108
+
109
+ 调用方 Client 的 `scopeRoleRefs: ["backend-api/reader"]` 单独限定 Token 可携带的角色范围;它不等于 Audience,也不授予用户或服务账号角色。角色授予继续通过角色关系草稿和统一发布完成。