@pactor-app/skills 1.33.0 → 1.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/package.json +1 -1
  2. package/pactor-prd/SKILL.md +20 -23
  3. package/pactor-prd/references/acceptance-checklist.md +1 -1
  4. package/pactor-prd/references/data-api.md +35 -0
  5. package/pactor-prd/references/incremental-wireframe-delta.md +8 -9
  6. package/pactor-prd/references/page-inventory-and-files.md +2 -2
  7. package/pactor-prd/references/page-templates.md +59 -12
  8. package/pactor-prd/references/project-structure.md +1 -1
  9. package/pactor-prd/template/README.md +4 -4
  10. package/pactor-prd/template/app/api/d/[...parts]/route.ts +80 -0
  11. package/pactor-prd/template/app/layout.tsx +1 -3
  12. package/pactor-prd/template/next-env.d.ts +2 -2
  13. package/pactor-prd/template/next.config.js +2 -2
  14. package/pactor-prd/template/package.json +4 -4
  15. package/pactor-prd/template/pnpm-lock.yaml +97 -97
  16. package/pactor-prd/template/src/pactor/App.tsx +3 -2
  17. package/pactor-prd/template/src/pactor/actions.ts +5 -431
  18. package/pactor-prd/template/src/pactor/config.ts +12 -4
  19. package/pactor-prd/template/src/server/yaml/common/dashboard.yaml +1 -1
  20. package/pactor-prd/template/src/server/yaml/common/login.yaml +46 -75
  21. package/pactor-prd/template/src/server/yaml/models/data-list.yaml +344 -0
  22. package/pactor-prd/template/src/server/yaml/provider/provider-detail.yaml +2 -2
  23. package/pactor-prd/template/src/server/yaml/provider/provider-edit.yaml +1 -1
  24. package/pactor-prd/template/src/server/yaml/provider/provider-list.yaml +1 -1
  25. package/pactor-prd/template/src/server/yaml/route/route-detail.yaml +1 -1
  26. package/pactor-prd/template/src/server/yaml/route/route-edit.yaml +1 -1
  27. package/pactor-prd/template/src/server/yaml/route/route-list.yaml +1 -1
  28. package/pactor-prd/template/src/server/yaml/sitemap.yaml +23 -6
  29. package/pactor-prd/references/mock-data-routes.md +0 -66
  30. package/pactor-prd/template/app/api/data/[...parts]/route.ts +0 -118
  31. package/pactor-prd/template/app/login.css +0 -122
  32. package/pactor-prd/template/src/pactor/mocks/audit-mock.ts +0 -403
  33. package/pactor-prd/template/src/pactor/mocks/call-logs-mock.ts +0 -875
  34. package/pactor-prd/template/src/pactor/mocks/client-debug-mock.ts +0 -188
  35. package/pactor-prd/template/src/pactor/mocks/client-templates-mock.ts +0 -497
  36. package/pactor-prd/template/src/pactor/mocks/clients-mock.ts +0 -483
  37. package/pactor-prd/template/src/pactor/mocks/costs-mock.ts +0 -406
  38. package/pactor-prd/template/src/pactor/mocks/dashboard-mock.ts +0 -192
  39. package/pactor-prd/template/src/pactor/mocks/model-debug-mock.ts +0 -144
  40. package/pactor-prd/template/src/pactor/mocks/models-mock.ts +0 -799
  41. package/pactor-prd/template/src/pactor/mocks/ops-usage-mock.ts +0 -806
  42. package/pactor-prd/template/src/pactor/mocks/providers-mock.ts +0 -424
  43. package/pactor-prd/template/src/pactor/mocks/routes-mock.ts +0 -604
  44. package/pactor-prd/template/src/pactor/services.ts +0 -185
@@ -1,122 +0,0 @@
1
- /* 登录页视觉优化:居中渐变背景 + 卡片/表单细节打磨。
2
- 作用域限定 .login-page;DSL 不支持自定义 className,
3
- 故经 Pactor 组件的 data-slot 钩子定位(须在 @pactor-app/ui/styles.css 之后加载)。 */
4
-
5
- .login-page {
6
- flex: 1;
7
- min-height: 100%;
8
- display: flex;
9
- align-items: center;
10
- justify-content: center;
11
- padding: 3rem 1rem;
12
- background: radial-gradient(circle at 20% 15%, rgba(128, 165, 160, .2), transparent 32%), radial-gradient(circle at 85% 88%, rgba(223, 127, 71, .1), transparent 34%), #fff;
13
- }
14
-
15
- .login-card {
16
- width: min(100%, 420px);
17
- padding: 32px 28px;
18
- border-radius: 16px;
19
- background: rgba(250, 250, 249, .78);
20
- backdrop-filter: blur(18px);
21
- -webkit-backdrop-filter: blur(18px);
22
- box-shadow: 0 24px 70px rgba(35, 42, 39, .14);
23
- }
24
-
25
- @media (prefers-color-scheme: dark) {
26
- .login-page {
27
- background:
28
- radial-gradient(circle at 20% 15%, rgb(128 165 160 / 0.16), transparent 34%),
29
- radial-gradient(circle at 85% 88%, rgb(223 127 71 / 0.08), transparent 36%),
30
- #0e1211;
31
- }
32
-
33
- /* 登录卡片:磨砂底转为深色半透明,边框按暗场调整 */
34
- .login-card {
35
- background: rgb(22 27 25 / 0.72);
36
- border-color: rgb(255 255 255 / 0.08);
37
- box-shadow: 0 24px 70px rgba(35, 42, 39, .14);
38
- }
39
-
40
- .login-page [data-slot="button"]:hover {
41
- box-shadow: 0 6px 16px -6px rgb(0 0 0 / 0.6);
42
- }
43
- }
44
-
45
- /* 登录卡片:更圆、入场动画(全站 Card 无阴影,见 theme.css) */
46
- .login-page [data-slot="card"] {
47
- width: 100%;
48
- max-width: 26rem;
49
- border-radius: calc(var(--radius) * 2);
50
- animation: login-card-in 0.45s cubic-bezier(0.21, 1.02, 0.73, 1) both;
51
- }
52
-
53
- @keyframes login-card-in {
54
- from {
55
- opacity: 0;
56
- transform: translateY(12px) scale(0.98);
57
- }
58
- to {
59
- opacity: 1;
60
- transform: none;
61
- }
62
- }
63
-
64
- /* 标题区三行文字(RESTRICTED ACCESS / 管理后台登录 / 副标题),
65
- Text 组件经 className 透传定位;卡片内容 gap 较宽,用负 margin 收紧组内间距 */
66
- .login-page .login-eyebrow {
67
- display: block;
68
- font-family: var(--font-geist-mono), ui-monospace, monospace;
69
- font-size: 0.75rem;
70
- letter-spacing: 0.18em;
71
- text-transform: uppercase;
72
- color: var(--primary);
73
- margin-bottom: 12px;
74
- }
75
-
76
- .login-page .login-heading {
77
- display: block;
78
- margin-top: -0.375rem;
79
- font-size: 1.5rem;
80
- font-weight: 700;
81
- letter-spacing: 0.01em;
82
- margin-bottom: 24px;
83
- }
84
-
85
- .login-page .login-subtitle {
86
- display: block;
87
- margin-top: -0.375rem;
88
- font-size: 0.875rem;
89
- margin-bottom: 28px;
90
- }
91
-
92
- .login-page .login-demo-hint {
93
- display: block;
94
- font-size: 0.8125rem;
95
- }
96
-
97
- /* 提示条圆角跟随卡片 */
98
- .login-page [data-slot="alert"] {
99
- border-radius: calc(var(--radius) * 1.2);
100
- }
101
-
102
- /* 输入框加高 */
103
- .login-page [data-slot="input"] {
104
- height: 2.75rem;
105
- }
106
-
107
- /* 登录按钮:加高、加粗、悬浮/按压反馈 */
108
- .login-page [data-slot="button"] {
109
- height: 2.75rem;
110
- font-weight: 600;
111
- transition:
112
- transform 0.15s ease,
113
- box-shadow 0.15s ease;
114
- }
115
-
116
- .login-page [data-slot="button"]:hover {
117
- box-shadow: 0 6px 16px -6px rgb(15 23 42 / 0.35);
118
- }
119
-
120
- .login-page [data-slot="button"]:active {
121
- transform: translateY(1px);
122
- }
@@ -1,403 +0,0 @@
1
- /**
2
- * 审计日志(系统管理)演示数据服务(MVP mock,静态页面)。
3
- * audit.list / audit.detail 注册为 Pactor service;接入真实后端后替换为
4
- * http / service 数据源,DSL 绑定路径保持不变。
5
- * 数据形态对齐 PRD《系统管理/02-审计》:列表(Timestamp / Operator / Operation /
6
- * Resource Type / Resource ID / IP)+ 详情(变更前 / 变更后 / Diff / 操作上下文
7
- * 四个 Tab,敏感数据脱敏显示)。
8
- * 审计范围覆盖 Provider / Model / Alias / Route / Client / Quota / RateLimit /
9
- * Pricing / 服务设置 / AppKey 创建停用 / Secret Rotation。
10
- * Diff 行与复合文案全部在 mock 层预计算(表达式引擎不支持数组方法与函数调用)。
11
- */
12
-
13
- export interface AuditDiffLine {
14
- type: "add" | "remove" | "same";
15
- text: string;
16
- }
17
-
18
- export interface AuditContextRow {
19
- label: string;
20
- value: string;
21
- }
22
-
23
- export interface AuditRecord {
24
- id: string;
25
- /** ISO 日期(yyyy-MM-dd),时间范围过滤用 */
26
- date: string;
27
- /** 完整时间戳(UTC+8 展示口径) */
28
- timeUtc: string;
29
- /** 列表短格式 MM-DD HH:mm */
30
- timeShort: string;
31
- operator: string;
32
- /** 操作展示名(修改 / 创建AppKey / Rotate Secret …) */
33
- operation: string;
34
- /** 操作类型过滤值 */
35
- operationType: string;
36
- /** 资源类型展示名(Route Policy / API Client …) */
37
- resourceType: string;
38
- /** 资源类型过滤值 */
39
- resourceTypeKey: string;
40
- resourceId: string;
41
- ip: string;
42
- requestId: string;
43
- userAgent: string;
44
- /** null = 该操作无此侧快照(创建无变更前 / 删除无变更后) */
45
- beforeJson: string | null;
46
- afterJson: string | null;
47
- diffLines: AuditDiffLine[];
48
- context: AuditContextRow[];
49
- }
50
-
51
- const OPERATION_LABELS: Record<string, string> = {
52
- create: "创建",
53
- update: "修改",
54
- delete: "删除",
55
- enable: "启用",
56
- disable: "停用",
57
- "appkey-create": "创建AppKey",
58
- "appkey-disable": "停用AppKey",
59
- "secret-rotate": "Rotate Secret",
60
- "settings-update": "修改服务设置",
61
- };
62
-
63
- const RESOURCE_TYPE_LABELS: Record<string, string> = {
64
- provider: "Provider",
65
- model: "Model",
66
- alias: "Model Alias",
67
- route: "Route",
68
- "route-policy": "Route Policy",
69
- client: "API Client",
70
- appkey: "AppKey",
71
- quota: "Quota Policy",
72
- ratelimit: "RateLimit Policy",
73
- pricing: "Pricing",
74
- settings: "服务设置",
75
- };
76
-
77
- export const OPERATOR_OPTIONS = [
78
- { label: "全部操作人", value: "all" },
79
- { label: "张三", value: "张三" },
80
- { label: "李四", value: "李四" },
81
- { label: "王五", value: "王五" },
82
- { label: "管理员", value: "管理员" },
83
- ];
84
-
85
- export const OPERATION_OPTIONS = [
86
- { label: "全部操作类型", value: "all" },
87
- ...Object.entries(OPERATION_LABELS).map(([value, label]) => ({
88
- label,
89
- value,
90
- })),
91
- ];
92
-
93
- export const RESOURCE_TYPE_OPTIONS = [
94
- { label: "全部资源类型", value: "all" },
95
- ...Object.entries(RESOURCE_TYPE_LABELS).map(([value, label]) => ({
96
- label,
97
- value,
98
- })),
99
- ];
100
-
101
- /** 原始条目:[日期时间, 操作人, 操作类型, 资源类型, Resource ID, IP, 变更前, 变更后] */
102
- type RawEntry = [
103
- string,
104
- string,
105
- string,
106
- string,
107
- string,
108
- string,
109
- Record<string, unknown> | null,
110
- Record<string, unknown> | null,
111
- ];
112
-
113
- const RAW: RawEntry[] = [
114
- [
115
- "2026-09-18 14:20:03",
116
- "张三",
117
- "update",
118
- "route-policy",
119
- "reasoning-def",
120
- "10.0.1.5",
121
- { policy: "fallback", maxRetries: 2, timeoutMs: 30000 },
122
- { policy: "fallback", maxRetries: 3, timeoutMs: 60000 },
123
- ],
124
- [
125
- "2026-09-18 10:00:41",
126
- "李四",
127
- "appkey-create",
128
- "client",
129
- "agent-app",
130
- "10.0.1.8",
131
- null,
132
- {
133
- appKeyId: "ak-2f8c1d9e",
134
- secret: "sk-****3f9a",
135
- client: "agent-app",
136
- status: "active",
137
- },
138
- ],
139
- [
140
- "2026-09-17 17:42:19",
141
- "管理员",
142
- "settings-update",
143
- "settings",
144
- "service-settings",
145
- "10.0.0.2",
146
- { promptPolicy: "masked", logRetentionDays: 90, currency: "USD" },
147
- { promptPolicy: "masked", logRetentionDays: 120, currency: "USD" },
148
- ],
149
- [
150
- "2026-09-17 11:05:52",
151
- "王五",
152
- "update",
153
- "pricing",
154
- "gpt-5-pro",
155
- "10.0.1.12",
156
- { inputPer1M: 12.0, outputPer1M: 48.0, currency: "USD" },
157
- { inputPer1M: 14.0, outputPer1M: 56.0, currency: "USD" },
158
- ],
159
- [
160
- "2026-09-16 16:33:08",
161
- "张三",
162
- "create",
163
- "route",
164
- "code-assist",
165
- "10.0.1.5",
166
- null,
167
- {
168
- code: "code-assist",
169
- targetModel: "claude-sonnet-4",
170
- fallback: ["gpt-5-pro"],
171
- status: "enabled",
172
- },
173
- ],
174
- [
175
- "2026-09-16 09:12:47",
176
- "李四",
177
- "disable",
178
- "provider",
179
- "azure-openai-east",
180
- "10.0.1.8",
181
- { status: "enabled", weight: 50, region: "eastus" },
182
- { status: "disabled", weight: 50, region: "eastus" },
183
- ],
184
- [
185
- "2026-09-15 15:58:26",
186
- "王五",
187
- "update",
188
- "quota",
189
- "agent-app-monthly",
190
- "10.0.1.12",
191
- { metric: "TOTAL_TOKEN", limit: 5000000, cycle: "month" },
192
- { metric: "TOTAL_TOKEN", limit: 8000000, cycle: "month" },
193
- ],
194
- [
195
- "2026-09-15 10:21:33",
196
- "张三",
197
- "secret-rotate",
198
- "appkey",
199
- "ak-7b31c904",
200
- "10.0.1.5",
201
- { appKeyId: "ak-7b31c904", secret: "sk-****a1c2" },
202
- { appKeyId: "ak-7b31c904", secret: "sk-****e7d4" },
203
- ],
204
- [
205
- "2026-09-14 18:44:09",
206
- "管理员",
207
- "update",
208
- "model",
209
- "gpt-5-pro",
210
- "10.0.0.2",
211
- { contextWindow: 272000, maxOutput: 32768, capabilities: ["tools"] },
212
- {
213
- contextWindow: 272000,
214
- maxOutput: 65536,
215
- capabilities: ["tools", "reasoning"],
216
- },
217
- ],
218
- [
219
- "2026-09-14 09:37:55",
220
- "李四",
221
- "appkey-disable",
222
- "appkey",
223
- "ak-9d20f153",
224
- "10.0.1.8",
225
- { appKeyId: "ak-9d20f153", client: "expired-trial", status: "active" },
226
- { appKeyId: "ak-9d20f153", client: "expired-trial", status: "disabled" },
227
- ],
228
- [
229
- "2026-09-13 14:02:18",
230
- "王五",
231
- "create",
232
- "ratelimit",
233
- "agent-app-rpm",
234
- "10.0.1.12",
235
- null,
236
- { metric: "REQUEST", limit: 600, window: "1m", mode: "hard" },
237
- ],
238
- [
239
- "2026-09-13 08:59:44",
240
- "张三",
241
- "update",
242
- "alias",
243
- "smart-default",
244
- "10.0.1.5",
245
- { alias: "smart-default", pointsTo: "gpt-5-pro" },
246
- { alias: "smart-default", pointsTo: "claude-sonnet-4" },
247
- ],
248
- [
249
- "2026-09-12 19:26:31",
250
- "管理员",
251
- "delete",
252
- "client",
253
- "legacy-bot",
254
- "10.0.0.2",
255
- {
256
- code: "legacy-bot",
257
- name: "Legacy Bot",
258
- appKeyId: "ak-00c4de11",
259
- status: "disabled",
260
- },
261
- null,
262
- ],
263
- [
264
- "2026-08-29 11:15:07",
265
- "李四",
266
- "enable",
267
- "provider",
268
- "openai-main",
269
- "10.0.1.8",
270
- { status: "disabled", weight: 100, region: "us-east-1" },
271
- { status: "enabled", weight: 100, region: "us-east-1" },
272
- ],
273
- [
274
- "2026-08-21 16:48:53",
275
- "张三",
276
- "settings-update",
277
- "settings",
278
- "service-settings",
279
- "10.0.1.5",
280
- { timezone: "UTC", currencyDecimals: 4 },
281
- { timezone: "Asia/Shanghai", currencyDecimals: 4 },
282
- ],
283
- ];
284
-
285
- function pretty(obj: Record<string, unknown> | null): string | null {
286
- return obj ? JSON.stringify(obj, null, 2) : null;
287
- }
288
-
289
- /** 行级对齐 diff:同位相同 → same;仅变更后 → add;仅变更前 → remove;均不同 → remove+add */
290
- function diffLines(before: string | null, after: string | null): AuditDiffLine[] {
291
- const b = before?.split("\n") ?? [];
292
- const a = after?.split("\n") ?? [];
293
- const lines: AuditDiffLine[] = [];
294
- const n = Math.max(a.length, b.length);
295
- for (let i = 0; i < n; i++) {
296
- const al = a[i];
297
- const bl = b[i];
298
- if (al === bl) {
299
- lines.push({ type: "same", text: ` ${al ?? ""}` });
300
- } else {
301
- if (bl !== undefined) lines.push({ type: "remove", text: `- ${bl}` });
302
- if (al !== undefined) lines.push({ type: "add", text: `+ ${al}` });
303
- }
304
- }
305
- return lines;
306
- }
307
-
308
- function build(): AuditRecord[] {
309
- return RAW.map((raw, i) => {
310
- const [time, operator, opType, resType, resourceId, ip, before, after] =
311
- raw;
312
- const beforeJson = pretty(before);
313
- const afterJson = pretty(after);
314
- const id = `aud-${String(1000 + i)}`;
315
- return {
316
- id,
317
- date: time.slice(0, 10),
318
- timeUtc: `${time} (UTC+8)`,
319
- timeShort: time.slice(5, 16),
320
- operator,
321
- operation: OPERATION_LABELS[opType],
322
- operationType: opType,
323
- resourceType: RESOURCE_TYPE_LABELS[resType],
324
- resourceTypeKey: resType,
325
- resourceId,
326
- ip,
327
- requestId: `req-audit-${(92140 + i * 37).toString(16)}`,
328
- userAgent: "GateWeave Console/1.0 (Chrome 139; macOS)",
329
- beforeJson,
330
- afterJson,
331
- diffLines: diffLines(beforeJson, afterJson),
332
- context: [
333
- { label: "操作人", value: operator },
334
- { label: "操作类型", value: OPERATION_LABELS[opType] },
335
- { label: "资源", value: `${RESOURCE_TYPE_LABELS[resType]} / ${resourceId}` },
336
- { label: "来源", value: "管理控制台" },
337
- { label: "User-Agent", value: "GateWeave Console/1.0 (Chrome 139; macOS)" },
338
- { label: "会话", value: `sess-${(5520 + i * 13).toString(16)}` },
339
- { label: "结果", value: "成功" },
340
- ],
341
- };
342
- });
343
- }
344
-
345
- const AUDITS = build();
346
-
347
- export const AUDIT_IDS = AUDITS.map((r) => r.id);
348
-
349
- export interface AuditQuery {
350
- start?: string;
351
- end?: string;
352
- operator?: string;
353
- operation?: string;
354
- resourceType?: string;
355
- resourceId?: string;
356
- }
357
-
358
- export function queryAudits(q: AuditQuery): {
359
- items: AuditRecord[];
360
- filteredText: string;
361
- } {
362
- const items = AUDITS.filter((r) => {
363
- if (q.start && r.date < q.start) return false;
364
- if (q.end && r.date > q.end) return false;
365
- if (q.operator && q.operator !== "all" && r.operator !== q.operator)
366
- return false;
367
- if (
368
- q.operation &&
369
- q.operation !== "all" &&
370
- r.operationType !== q.operation
371
- )
372
- return false;
373
- if (
374
- q.resourceType &&
375
- q.resourceType !== "all" &&
376
- r.resourceTypeKey !== q.resourceType
377
- )
378
- return false;
379
- if (
380
- q.resourceId &&
381
- !r.resourceId.toLowerCase().includes(q.resourceId.toLowerCase())
382
- )
383
- return false;
384
- return true;
385
- });
386
- return {
387
- items,
388
- filteredText: items.length.toLocaleString("en-US"),
389
- };
390
- }
391
-
392
- export function getAudit(id: string): AuditRecord | undefined {
393
- return AUDITS.find((r) => r.id === id);
394
- }
395
-
396
- /** 操作人筛选项(Select options):「全部」+ 记录中去重的操作人 */
397
- export function listAuditOperators(): { label: string; value: string }[] {
398
- const names = [...new Set(AUDITS.map((r) => r.operator))];
399
- return [
400
- { label: "全部操作人", value: "all" },
401
- ...names.map((name) => ({ label: name, value: name })),
402
- ];
403
- }