@ai-content-space/loopx 0.1.2 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/README.md +422 -57
  2. package/README.zh-CN.md +485 -0
  3. package/assets/logo.svg +89 -0
  4. package/package.json +5 -1
  5. package/plugins/loopx/.codex-plugin/plugin.json +1 -1
  6. package/plugins/loopx/scripts/plugin-install.test.mjs +14 -0
  7. package/plugins/loopx/skills/archive/SKILL.md +49 -0
  8. package/plugins/loopx/skills/build/SKILL.md +111 -9
  9. package/plugins/loopx/skills/clarify/SKILL.md +129 -8
  10. package/plugins/loopx/skills/debug/SKILL.md +296 -0
  11. package/plugins/loopx/skills/debug/condition-based-waiting.md +115 -0
  12. package/plugins/loopx/skills/debug/defense-in-depth.md +122 -0
  13. package/plugins/loopx/skills/debug/find-polluter.sh +63 -0
  14. package/plugins/loopx/skills/debug/root-cause-tracing.md +169 -0
  15. package/plugins/loopx/skills/go-style/SKILL.md +71 -0
  16. package/plugins/loopx/skills/kratos/SKILL.md +74 -0
  17. package/plugins/loopx/skills/kratos/references/advanced-features.md +314 -0
  18. package/plugins/loopx/skills/kratos/references/architecture.md +488 -0
  19. package/plugins/loopx/skills/kratos/references/configuration.md +399 -0
  20. package/plugins/loopx/skills/kratos/references/http-customization.md +512 -0
  21. package/plugins/loopx/skills/kratos/references/middleware-logging.md +400 -0
  22. package/plugins/loopx/skills/kratos/references/proto-api-design.md +432 -0
  23. package/plugins/loopx/skills/kratos/references/security-auth.md +411 -0
  24. package/plugins/loopx/skills/kratos/references/troubleshooting.md +385 -0
  25. package/plugins/loopx/skills/plan/SKILL.md +24 -3
  26. package/plugins/loopx/skills/review/SKILL.md +98 -1
  27. package/plugins/loopx/skills/tdd/SKILL.md +371 -0
  28. package/plugins/loopx/skills/tdd/testing-anti-patterns.md +299 -0
  29. package/plugins/loopx/skills/verify/SKILL.md +139 -0
  30. package/scripts/codex-stop-hook.mjs +71 -0
  31. package/scripts/codex-workflow-hook.mjs +248 -0
  32. package/skills/archive/SKILL.md +49 -0
  33. package/skills/build/SKILL.md +111 -9
  34. package/skills/clarify/SKILL.md +129 -8
  35. package/skills/debug/SKILL.md +296 -0
  36. package/skills/debug/condition-based-waiting.md +115 -0
  37. package/skills/debug/defense-in-depth.md +122 -0
  38. package/skills/debug/find-polluter.sh +63 -0
  39. package/skills/debug/root-cause-tracing.md +169 -0
  40. package/skills/go-style/SKILL.md +71 -0
  41. package/skills/kratos/SKILL.md +74 -0
  42. package/skills/kratos/references/advanced-features.md +314 -0
  43. package/skills/kratos/references/architecture.md +488 -0
  44. package/skills/kratos/references/configuration.md +399 -0
  45. package/skills/kratos/references/http-customization.md +512 -0
  46. package/skills/kratos/references/middleware-logging.md +400 -0
  47. package/skills/kratos/references/proto-api-design.md +432 -0
  48. package/skills/kratos/references/security-auth.md +411 -0
  49. package/skills/kratos/references/troubleshooting.md +385 -0
  50. package/skills/plan/SKILL.md +20 -3
  51. package/skills/review/SKILL.md +98 -1
  52. package/skills/tdd/SKILL.md +371 -0
  53. package/skills/tdd/testing-anti-patterns.md +299 -0
  54. package/skills/verify/SKILL.md +139 -0
  55. package/src/build-runtime.mjs +311 -26
  56. package/src/build-stop-gate.mjs +94 -0
  57. package/src/cli.mjs +57 -5
  58. package/src/codex-exec-runtime.mjs +105 -5
  59. package/src/context-manifest.mjs +172 -0
  60. package/src/html-views.mjs +316 -0
  61. package/src/install-discovery.mjs +352 -5
  62. package/src/next-skill.mjs +57 -5
  63. package/src/plan-runtime.mjs +102 -122
  64. package/src/review-runtime.mjs +558 -0
  65. package/src/runtime-maintenance.mjs +429 -14
  66. package/src/template-governance.mjs +223 -0
  67. package/src/workflow.mjs +2341 -120
  68. package/src/workspace-context.mjs +166 -0
  69. package/src/workspace-memory.mjs +69 -0
@@ -0,0 +1,488 @@
1
+ # Architecture
2
+
3
+ Guide for Kratos layered architecture and dependency injection.
4
+
5
+ ## When to Use
6
+
7
+ - Structuring a new Kratos project
8
+ - Understanding layer responsibilities
9
+ - Setting up fx dependency injection
10
+ - Defining repository interfaces
11
+
12
+ ---
13
+
14
+ ## Layer Responsibilities
15
+
16
+ Kratos follows clean architecture with three primary layers:
17
+
18
+ ```
19
+ ┌─────────────────────────────────────────────┐
20
+ │ Service │
21
+ │ (Protocol conversion, simple validation) │
22
+ ├─────────────────────────────────────────────┤
23
+ │ Biz │
24
+ │ (Business logic, domain models, use cases) │
25
+ ├─────────────────────────────────────────────┤
26
+ │ Data │
27
+ │ (Data access, repositories, external APIs) │
28
+ └─────────────────────────────────────────────┘
29
+ ```
30
+
31
+ ### Service Layer
32
+
33
+ **Responsibility:** Protocol conversion and basic validation.
34
+
35
+ - Convert HTTP/gRPC requests to internal types
36
+ - Call biz layer with appropriate parameters
37
+ - Convert biz responses back to proto types
38
+ - Handle proto-level validation (protovalidate)
39
+
40
+ **Does NOT contain:** Business logic, data access, complex calculations
41
+
42
+ ```go
43
+ // Service layer - protocol conversion only
44
+ func (s *UserService) GetUser(ctx context.Context, req *v1.GetUserRequest) (*v1.GetUserResponse, error) {
45
+ // 1. Validate request (proto-level)
46
+ if err := s.validator.Validate(req); err != nil {
47
+ return nil, err
48
+ }
49
+
50
+ // 2. Call biz layer
51
+ user, err := s.uc.GetUser(ctx, req.UserId)
52
+ if err != nil {
53
+ return nil, err
54
+ }
55
+
56
+ // 3. Convert to proto response
57
+ return &v1.GetUserResponse{
58
+ Name: user.Name,
59
+ Email: user.Email,
60
+ }, nil
61
+ }
62
+ ```
63
+
64
+ ### Biz Layer
65
+
66
+ **Responsibility:** Business logic and domain rules.
67
+
68
+ - Implement business rules and workflows
69
+ - Define domain entities (not proto types)
70
+ - Coordinate between repositories
71
+ - Handle business-level errors
72
+
73
+ **Does NOT contain:** HTTP/gRPC details, database queries, proto types
74
+
75
+ ```go
76
+ // Biz layer - business logic only
77
+ type User struct {
78
+ ID int64
79
+ Name string
80
+ Email string
81
+ }
82
+
83
+ type UserUseCase struct {
84
+ repo UserRepo
85
+ log *log.Helper
86
+ }
87
+
88
+ func (uc *UserUseCase) GetUser(ctx context.Context, id string) (*User, error) {
89
+ uc.log.WithContext(ctx).Infof("Getting user: %s", id)
90
+
91
+ // Business logic: check permissions, apply rules
92
+ user, err := uc.repo.FindByID(ctx, id)
93
+ if err != nil {
94
+ return nil, v1.ErrorUserNotFound("user %s not found", id)
95
+ }
96
+
97
+ // Business rule: inactive users not accessible
98
+ if user.Status == "inactive" {
99
+ return nil, errors.New(403, "FORBIDDEN", "user is inactive")
100
+ }
101
+
102
+ return user, nil
103
+ }
104
+ ```
105
+
106
+ ### Data Layer
107
+
108
+ **Responsibility:** Data access and external service integration.
109
+
110
+ - Implement repository interfaces
111
+ - Database operations (SQL, NoSQL)
112
+ - External API calls
113
+ - Cache management
114
+
115
+ **Does NOT contain:** Business logic, protocol handling
116
+
117
+ ```go
118
+ // Data layer - data access only
119
+ type userRepo struct {
120
+ db *gorm.DB
121
+ log *log.Helper
122
+ }
123
+
124
+ func (r *userRepo) FindByID(ctx context.Context, id string) (*biz.User, error) {
125
+ var model UserModel
126
+ if err := r.db.WithContext(ctx).Where("id = ?", id).First(&model).Error; err != nil {
127
+ return nil, err
128
+ }
129
+ return &biz.User{
130
+ ID: model.ID,
131
+ Name: model.Name,
132
+ Email: model.Email,
133
+ }, nil
134
+ }
135
+ ```
136
+
137
+ ---
138
+
139
+ ## Dependency Injection
140
+
141
+ Kratos supports two DI approaches: **wire** (official Kratos layout) and **fx** (alternative).
142
+
143
+ ### Wire (Official Kratos Layout)
144
+
145
+ Wire is Google's compile-time dependency injection tool, used in official Kratos project templates.
146
+
147
+ **Install:**
148
+ ```bash
149
+ go install github.com/google/wire/cmd/wire@latest
150
+ ```
151
+
152
+ **Wire.go definition:**
153
+ ```go
154
+ // go build will ignore this file, but wire uses it
155
+
156
+ //+build wireinject
157
+
158
+ package main
159
+
160
+ import (
161
+ "github.com/google/wire"
162
+ "github.com/go-kratos/kratos/v2"
163
+ "github.com/go-kratos/kratos/v2/log"
164
+ "github.com/myorg/myproject/internal/biz"
165
+ "github.com/myorg/myproject/internal/data"
166
+ "github.com/myorg/myproject/internal/server"
167
+ "github.com/myorg/myproject/internal/service"
168
+ )
169
+
170
+ func wireApp(*conf.Server, *conf.Data, log.Logger) (*kratos.App, func(), error) {
171
+ panic(wire.Build(
172
+ data.ProviderSet,
173
+ biz.ProviderSet,
174
+ service.ProviderSet,
175
+ server.ProviderSet,
176
+ newApp,
177
+ ))
178
+ }
179
+ ```
180
+
181
+ **ProviderSet in each layer:**
182
+ ```go
183
+ // internal/data/data.go
184
+ var ProviderSet = wire.NewSet(NewData, NewUserRepo)
185
+
186
+ // internal/biz/biz.go
187
+ var ProviderSet = wire.NewSet(NewUserUseCase)
188
+
189
+ // internal/service/service.go
190
+ var ProviderSet = wire.NewSet(NewUserService)
191
+
192
+ // internal/server/server.go
193
+ var ProviderSet = wire.NewSet(NewHTTPServer, NewGRPCServer)
194
+ ```
195
+
196
+ **Generate wire_gen.go:**
197
+ ```bash
198
+ wire ./cmd/server
199
+ ```
200
+
201
+ **Advantages:**
202
+ - Compile-time verification (errors caught before runtime)
203
+ - No runtime reflection overhead
204
+ - Clear dependency graph visible in generated code
205
+ - Official Kratos template uses this approach
206
+
207
+ ---
208
+
209
+ ### fx (Alternative - Uber's DI)
210
+
211
+ fx is Uber's runtime dependency injection framework.
212
+
213
+ ## fx Dependency Injection
214
+
215
+ Kratos also supports Uber fx for dependency injection:
216
+
217
+ ### Module Pattern
218
+
219
+ Organize dependencies into modules:
220
+
221
+ ```go
222
+ // internal/service/fx.go
223
+ package service
224
+
225
+ import "go.uber.org/fx"
226
+
227
+ var Module = fx.Options(
228
+ fx.Provide(NewUserService),
229
+ fx.Provide(NewOrderService),
230
+ )
231
+
232
+ // internal/biz/fx.go
233
+ package biz
234
+
235
+ var Module = fx.Options(
236
+ fx.Provide(NewUserUseCase),
237
+ fx.Provide(NewOrderUseCase),
238
+ )
239
+
240
+ // internal/data/fx.go
241
+ package data
242
+
243
+ var Module = fx.Options(
244
+ fx.Provide(NewUserRepo),
245
+ fx.Provide(NewData), // DB connection
246
+ )
247
+
248
+ // internal/server/fx.go
249
+ package server
250
+
251
+ var Module = fx.Options(
252
+ fx.Provide(NewHTTPServer),
253
+ fx.Provide(NewGRPCServer),
254
+ )
255
+ ```
256
+
257
+ ### Main Application
258
+
259
+ ```go
260
+ // cmd/server/main.go
261
+ package main
262
+
263
+ import (
264
+ "github.com/myorg/myproject/internal/biz"
265
+ "github.com/myorg/myproject/internal/data"
266
+ "github.com/myorg/myproject/internal/server"
267
+ "github.com/myorg/myproject/internal/service"
268
+ "go.uber.org/fx"
269
+ )
270
+
271
+ func main() {
272
+ app := fx.New(
273
+ // Provide configs
274
+ fx.Provide(provideConfigs),
275
+ fx.Provide(provideLogger),
276
+ fx.Provide(provideValidator),
277
+
278
+ // Include modules
279
+ server.Module,
280
+ data.Module,
281
+ biz.Module,
282
+ service.Module,
283
+
284
+ // Provide Kratos app
285
+ appModule,
286
+ )
287
+ app.Run()
288
+ }
289
+ ```
290
+
291
+ ### Dependency Flow
292
+
293
+ ```
294
+ fx.New() resolves dependencies:
295
+
296
+ provideConfigs → Bootstrap
297
+ provideLogger → log.Logger
298
+ provideValidator → protovalidate.Validator
299
+
300
+ data.Module:
301
+ NewData(Bootstrap) → *gorm.DB
302
+ NewUserRepo(*gorm.DB, log.Logger) → biz.UserRepo
303
+
304
+ biz.Module:
305
+ NewUserUseCase(biz.UserRepo, log.Logger) → *UserUseCase
306
+
307
+ service.Module:
308
+ NewUserService(*UserUseCase, log.Logger, protovalidate.Validator) → *UserService
309
+
310
+ server.Module:
311
+ NewHTTPServer(Bootstrap, *UserService, log.Logger) → *http.Server
312
+ ```
313
+
314
+ ---
315
+
316
+ ## Repository Interface Pattern
317
+
318
+ Define repository interfaces in biz layer, implement in data layer:
319
+
320
+ ### Interface Definition (Biz)
321
+
322
+ ```go
323
+ // internal/biz/user.go
324
+ package biz
325
+
326
+ import "context"
327
+
328
+ // UserRepo interface - defined in biz, implemented in data
329
+ type UserRepo interface {
330
+ Save(ctx context.Context, user *User) (*User, error)
331
+ FindByID(ctx context.Context, id int64) (*User, error)
332
+ FindByEmail(ctx context.Context, email string) (*User, error)
333
+ Update(ctx context.Context, user *User) (*User, error)
334
+ Delete(ctx context.Context, id int64) error
335
+ ListAll(ctx context.Context) ([]*User, error)
336
+ }
337
+ ```
338
+
339
+ ### Implementation (Data)
340
+
341
+ ```go
342
+ // internal/data/user.go
343
+ package data
344
+
345
+ import (
346
+ "context"
347
+ "github.com/myorg/myproject/internal/biz"
348
+ "github.com/go-kratos/kratos/v2/log"
349
+ )
350
+
351
+ type userRepo struct {
352
+ data *Data
353
+ log *log.Helper
354
+ }
355
+
356
+ // NewUserRepo implements biz.UserRepo interface
357
+ func NewUserRepo(data *Data, logger log.Logger) biz.UserRepo {
358
+ return &userRepo{
359
+ data: data,
360
+ log: log.NewHelper(logger),
361
+ }
362
+ }
363
+
364
+ func (r *userRepo) Save(ctx context.Context, user *biz.User) (*biz.User, error) {
365
+ // Database implementation
366
+ return user, nil
367
+ }
368
+ ```
369
+
370
+ **Why this matters:** Biz layer doesn't know about database details. You can swap databases without changing business logic.
371
+
372
+ ---
373
+
374
+ ## Custom Route Middleware Inheritance
375
+
376
+ For non-proto routes (file upload, WebSocket), inherit server middleware:
377
+
378
+ ```go
379
+ // internal/server/http.go
380
+ func NewHTTPServer(c *conf.Server, greeter *service.GreeterService, logger log.Logger) *http.Server {
381
+ opts := []http.ServerOption{
382
+ http.Middleware(
383
+ recovery.Recovery(),
384
+ auth.AuthToken(),
385
+ ),
386
+ }
387
+
388
+ srv := http.NewServer(opts...)
389
+
390
+ // Proto-generated routes (automatic middleware)
391
+ v1.RegisterGreeterServiceHTTPServer(srv, greeter)
392
+
393
+ // Custom route (manual middleware)
394
+ route := srv.Route("/")
395
+ route.POST("/v1/upload", greeter.UploadFile)
396
+
397
+ return srv
398
+ }
399
+
400
+ // service/upload.go
401
+ func (s *GreeterService) UploadFile(ctx http.Context) error {
402
+ // Set operation for middleware
403
+ http.SetOperation(ctx, "/upload.v1.UploadService/Upload")
404
+
405
+ // Bind request
406
+ var req UploadRequest
407
+ if err := ctx.BindQuery(&req); err != nil {
408
+ return err
409
+ }
410
+
411
+ // Use middleware chain
412
+ h := ctx.Middleware(func(ctx context.Context, req interface{}) (interface{}, error) {
413
+ return s.uc.UploadFile(ctx, req.(*UploadRequest))
414
+ })
415
+
416
+ resp, err := h(ctx, &req)
417
+ if err != nil {
418
+ return err
419
+ }
420
+
421
+ return ctx.JSON(200, resp)
422
+ }
423
+ ```
424
+
425
+ ---
426
+
427
+ ## pb → Struct Type Conversion
428
+
429
+ Use copier with copieroptpb for protobuf to Go struct conversion:
430
+
431
+ ### Install
432
+
433
+ ```bash
434
+ go get github.com/jinzhu/copier
435
+ go get github.com/tiny-lib/copieroptpb
436
+ ```
437
+
438
+ ### Usage
439
+
440
+ ```go
441
+ import (
442
+ "github.com/jinzhu/copier"
443
+ "github.com/tiny-lib/copieroptpb"
444
+ )
445
+
446
+ // biz layer struct
447
+ type User struct {
448
+ Name string
449
+ Email string
450
+ }
451
+
452
+ // Convert pb message to biz struct
453
+ func toBizUser(pbUser *v1.User) (*User, error) {
454
+ user := &User{}
455
+ if err := copier.CopyWithOption(pbUser, user, copieroptpb.Option()); err != nil {
456
+ return nil, err
457
+ }
458
+ return user, nil
459
+ }
460
+
461
+ // Convert biz struct to pb message
462
+ func toProtoUser(user *User) (*v1.User, error) {
463
+ pbUser := &v1.User{}
464
+ if err := copier.CopyWithOption(user, pbUser, copieroptpb.Option()); err != nil {
465
+ return nil, err
466
+ }
467
+ return pbUser, nil
468
+ }
469
+ ```
470
+
471
+ **Why copieroptpb:** Handles protobuf wrapper types (StringValue, Int32Value, etc.) that copier doesn't understand natively.
472
+
473
+ ---
474
+
475
+ ## Dependency Boundaries
476
+
477
+ Keep layers isolated:
478
+
479
+ | Layer | Allowed Dependencies |
480
+ |-------|---------------------|
481
+ | Service | Biz, proto types, kratos transport |
482
+ | Biz | Data (interfaces), domain types, errors |
483
+ | Data | Biz (interfaces), database drivers, external APIs |
484
+
485
+ **Forbidden:**
486
+ - Service → Data (skip biz layer)
487
+ - Data → Service (reverse dependency)
488
+ - Any layer → proto types in wrong context