@ai-content-space/loopx 0.1.2 → 0.1.3

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 (67) hide show
  1. package/README.md +343 -56
  2. package/README.zh-CN.md +392 -0
  3. package/package.json +4 -1
  4. package/plugins/loopx/.codex-plugin/plugin.json +1 -1
  5. package/plugins/loopx/scripts/plugin-install.test.mjs +1 -0
  6. package/plugins/loopx/skills/archive/SKILL.md +39 -0
  7. package/plugins/loopx/skills/build/SKILL.md +111 -9
  8. package/plugins/loopx/skills/clarify/SKILL.md +121 -1
  9. package/plugins/loopx/skills/debug/SKILL.md +296 -0
  10. package/plugins/loopx/skills/debug/condition-based-waiting.md +115 -0
  11. package/plugins/loopx/skills/debug/defense-in-depth.md +122 -0
  12. package/plugins/loopx/skills/debug/find-polluter.sh +63 -0
  13. package/plugins/loopx/skills/debug/root-cause-tracing.md +169 -0
  14. package/plugins/loopx/skills/go-style/SKILL.md +71 -0
  15. package/plugins/loopx/skills/kratos/SKILL.md +74 -0
  16. package/plugins/loopx/skills/kratos/references/advanced-features.md +314 -0
  17. package/plugins/loopx/skills/kratos/references/architecture.md +488 -0
  18. package/plugins/loopx/skills/kratos/references/configuration.md +399 -0
  19. package/plugins/loopx/skills/kratos/references/http-customization.md +512 -0
  20. package/plugins/loopx/skills/kratos/references/middleware-logging.md +400 -0
  21. package/plugins/loopx/skills/kratos/references/proto-api-design.md +432 -0
  22. package/plugins/loopx/skills/kratos/references/security-auth.md +411 -0
  23. package/plugins/loopx/skills/kratos/references/troubleshooting.md +385 -0
  24. package/plugins/loopx/skills/plan/SKILL.md +22 -2
  25. package/plugins/loopx/skills/review/SKILL.md +98 -1
  26. package/plugins/loopx/skills/tdd/SKILL.md +371 -0
  27. package/plugins/loopx/skills/tdd/testing-anti-patterns.md +299 -0
  28. package/plugins/loopx/skills/verify/SKILL.md +139 -0
  29. package/scripts/codex-stop-hook.mjs +71 -0
  30. package/scripts/codex-workflow-hook.mjs +153 -0
  31. package/skills/archive/SKILL.md +39 -0
  32. package/skills/build/SKILL.md +111 -9
  33. package/skills/clarify/SKILL.md +121 -1
  34. package/skills/debug/SKILL.md +296 -0
  35. package/skills/debug/condition-based-waiting.md +115 -0
  36. package/skills/debug/defense-in-depth.md +122 -0
  37. package/skills/debug/find-polluter.sh +63 -0
  38. package/skills/debug/root-cause-tracing.md +169 -0
  39. package/skills/go-style/SKILL.md +71 -0
  40. package/skills/kratos/SKILL.md +74 -0
  41. package/skills/kratos/references/advanced-features.md +314 -0
  42. package/skills/kratos/references/architecture.md +488 -0
  43. package/skills/kratos/references/configuration.md +399 -0
  44. package/skills/kratos/references/http-customization.md +512 -0
  45. package/skills/kratos/references/middleware-logging.md +400 -0
  46. package/skills/kratos/references/proto-api-design.md +432 -0
  47. package/skills/kratos/references/security-auth.md +411 -0
  48. package/skills/kratos/references/troubleshooting.md +385 -0
  49. package/skills/plan/SKILL.md +18 -2
  50. package/skills/review/SKILL.md +98 -1
  51. package/skills/tdd/SKILL.md +371 -0
  52. package/skills/tdd/testing-anti-patterns.md +299 -0
  53. package/skills/verify/SKILL.md +139 -0
  54. package/src/build-runtime.mjs +303 -26
  55. package/src/build-stop-gate.mjs +94 -0
  56. package/src/cli.mjs +47 -5
  57. package/src/codex-exec-runtime.mjs +105 -5
  58. package/src/context-manifest.mjs +172 -0
  59. package/src/install-discovery.mjs +352 -5
  60. package/src/next-skill.mjs +57 -5
  61. package/src/plan-runtime.mjs +79 -122
  62. package/src/review-runtime.mjs +378 -0
  63. package/src/runtime-maintenance.mjs +428 -14
  64. package/src/template-governance.mjs +223 -0
  65. package/src/workflow.mjs +1941 -117
  66. package/src/workspace-context.mjs +166 -0
  67. package/src/workspace-memory.mjs +69 -0
@@ -0,0 +1,399 @@
1
+ # Configuration
2
+
3
+ Guide for Kratos configuration management and startup hooks.
4
+
5
+ ## When to Use
6
+
7
+ - Setting up Bootstrap configuration
8
+ - Validating config before startup
9
+ - Adding startup/shutdown hooks
10
+ - Extending config format support
11
+
12
+ ---
13
+
14
+ ## Bootstrap Configuration Pattern
15
+
16
+ Use protobuf to define configuration with validation:
17
+
18
+ ### Proto Definition
19
+
20
+ ```protobuf
21
+ // internal/conf/conf.proto
22
+ syntax = "proto3";
23
+ package conf;
24
+
25
+ import "buf/validate/validate.proto";
26
+ import "google/protobuf/duration.proto";
27
+
28
+ option go_package = "github.com/myorg/myproject/internal/conf;conf";
29
+
30
+ message Bootstrap {
31
+ Server server = 1;
32
+ Data data = 2;
33
+ Log log = 3;
34
+ }
35
+
36
+ message Server {
37
+ message HTTP {
38
+ string network = 1;
39
+ string addr = 2;
40
+ google.protobuf.Duration timeout = 3 [
41
+ (buf.validate.field).required = true,
42
+ (buf.validate.field).duration = {
43
+ gt: {seconds: 1}
44
+ lte: {seconds: 600}
45
+ }
46
+ ];
47
+ }
48
+ message GRPC {
49
+ string network = 1;
50
+ string addr = 2;
51
+ google.protobuf.Duration timeout = 3 [
52
+ (buf.validate.field).required = true,
53
+ (buf.validate.field).duration = {
54
+ gt: {seconds: 1}
55
+ lte: {seconds: 600}
56
+ }
57
+ ];
58
+ }
59
+ HTTP http = 1;
60
+ GRPC grpc = 2;
61
+ }
62
+
63
+ message Data {
64
+ message Database {
65
+ string driver = 1;
66
+ string source = 2;
67
+ }
68
+ message Redis {
69
+ string network = 1;
70
+ string addr = 2;
71
+ google.protobuf.Duration read_timeout = 3;
72
+ google.protobuf.Duration write_timeout = 4;
73
+ }
74
+ Database database = 1;
75
+ Redis redis = 2;
76
+ }
77
+
78
+ enum LogLevel {
79
+ Debug = 0;
80
+ Info = 1;
81
+ Warn = 2;
82
+ Error = 3;
83
+ Fatal = 4;
84
+ }
85
+
86
+ message Log {
87
+ string log_path = 1;
88
+ LogLevel log_level = 2 [
89
+ (buf.validate.field).enum = {
90
+ defined_only: true
91
+ in: [0, 1, 2, 3, 4]
92
+ }
93
+ ];
94
+ int32 max_size = 3;
95
+ int32 max_keep_days = 4;
96
+ int32 max_keep_files = 5;
97
+ bool compress = 6;
98
+ }
99
+ ```
100
+
101
+ ### YAML Config File
102
+
103
+ ```yaml
104
+ # configs/config.yaml
105
+ server:
106
+ http:
107
+ addr: 0.0.0.0:8000
108
+ timeout: 10s
109
+ grpc:
110
+ addr: 0.0.0.0:9000
111
+ timeout: 10s
112
+
113
+ data:
114
+ database:
115
+ driver: mysql
116
+ source: user:pass@tcp(localhost:3306)/db?charset=utf8mb4
117
+ redis:
118
+ addr: localhost:6379
119
+ read_timeout: 0.5s
120
+ write_timeout: 0.5s
121
+
122
+ log:
123
+ log_path: /var/log/app.log
124
+ log_level: Info
125
+ max_size: 100
126
+ max_keep_days: 7
127
+ max_keep_files: 10
128
+ compress: true
129
+ ```
130
+
131
+ ---
132
+
133
+ ## Startup Validation
134
+
135
+ Validate configuration before application starts:
136
+
137
+ ```go
138
+ // cmd/server/main.go
139
+ package main
140
+
141
+ import (
142
+ "buf.build/go/protovalidate"
143
+ "github.com/go-kratos/kratos/v2/config"
144
+ "github.com/go-kratos/kratos/v2/config/file"
145
+ )
146
+
147
+ func provideConfigs(flagConf string) *conf.Bootstrap {
148
+ c := config.New(
149
+ config.WithSource(file.NewSource(flagConf)),
150
+ )
151
+
152
+ var bc conf.Bootstrap
153
+ if err := c.Scan(&bc); err != nil {
154
+ panic(err) // Startup failure - program cannot run without config
155
+ }
156
+
157
+ // Create validator
158
+ validator, err := protovalidate.New()
159
+ if err != nil {
160
+ panic(err) // Startup failure - validator is required
161
+ }
162
+
163
+ // Validate config before boot
164
+ if err := validator.Validate(&bc); err != nil {
165
+ panic(err) // Startup failure - invalid config is fatal
166
+ }
167
+
168
+ return &bc
169
+ }
170
+ ```
171
+
172
+ **Why panic is acceptable here:** This is startup code. If config is invalid, the application cannot run. Panics at startup are appropriate because there's no graceful recovery possible. For library/utility functions, prefer returning errors instead.
173
+ ```
174
+
175
+ **Why this matters:** Invalid config is caught at startup, not during operation. Proto-based validation keeps rules with data definition.
176
+
177
+ ---
178
+
179
+ ## Multi-Format Config Extension
180
+
181
+ Kratos supports json, yaml, proto, xml by default. Add other formats:
182
+
183
+ ### TOML Example
184
+
185
+ ```go
186
+ // internal/pkg/tomlencoding/toml.go
187
+ package tomlencoding
188
+
189
+ import (
190
+ "github.com/BurntSushi/toml"
191
+ "github.com/go-kratos/kratos/v2/encoding"
192
+ )
193
+
194
+ const Name = "toml"
195
+
196
+ func init() {
197
+ encoding.RegisterCodec(codec{})
198
+ }
199
+
200
+ type codec struct{}
201
+
202
+ func (codec) Marshal(v interface{}) ([]byte, error) {
203
+ return toml.Marshal(v)
204
+ }
205
+
206
+ func (codec) Unmarshal(data []byte, v interface{}) error {
207
+ return toml.Unmarshal(data, v)
208
+ }
209
+
210
+ func (codec) Name() string {
211
+ return Name
212
+ }
213
+ ```
214
+
215
+ ### Usage
216
+
217
+ ```go
218
+ // cmd/server/main.go
219
+ import _ "github.com/myorg/myproject/internal/pkg/tomlencoding"
220
+
221
+ // Now .toml files are supported
222
+ c := config.New(
223
+ config.WithSource(file.NewSource("configs")),
224
+ )
225
+ ```
226
+
227
+ ### Resolver for Key Normalization
228
+
229
+ Different formats use different key conventions (camelCase vs snake_case):
230
+
231
+ ```go
232
+ func resolver(input map[string]interface{}) error {
233
+ // Normalize keys: MyTitle → my_title
234
+ for key, value := range input {
235
+ normalizedKey := toSnakeCase(key)
236
+ if normalizedKey != key {
237
+ input[normalizedKey] = value
238
+ delete(input, key)
239
+ }
240
+ }
241
+ return nil
242
+ }
243
+
244
+ c := config.New(
245
+ config.WithSource(file.NewSource("configs")),
246
+ config.WithResolver(resolver),
247
+ )
248
+ ```
249
+
250
+ ---
251
+
252
+ ## Startup Hooks
253
+
254
+ Kratos v2.5.3+ provides lifecycle hooks:
255
+
256
+ ### Hook Types
257
+
258
+ ```go
259
+ // BeforeStart: Runs before server starts
260
+ // BeforeStop: Runs before server stops
261
+ // AfterStart: Runs after server starts
262
+ // AfterStop: Runs after server stops
263
+
264
+ app := kratos.New(
265
+ kratos.Name("my-app"),
266
+ kratos.Version("v1.0.0"),
267
+
268
+ kratos.BeforeStart(func(ctx context.Context) error {
269
+ log.Info("Initializing...")
270
+ // Initialize caches, warm up data
271
+ return nil
272
+ }),
273
+
274
+ kratos.AfterStart(func(ctx context.Context) error {
275
+ log.Info("Server started")
276
+ // Register with external systems
277
+ return nil
278
+ }),
279
+
280
+ kratos.BeforeStop(func(ctx context.Context) error {
281
+ log.Info("Shutting down...")
282
+ // Drain connections, save state
283
+ return nil
284
+ }),
285
+
286
+ kratos.AfterStop(func(ctx context.Context) error {
287
+ log.Info("Server stopped")
288
+ // Cleanup
289
+ return nil
290
+ }),
291
+ )
292
+ ```
293
+
294
+ ### Use Cases
295
+
296
+ | Hook | Common Uses |
297
+ |------|-------------|
298
+ | BeforeStart | Database warmup, cache pre-fill, config validation |
299
+ | AfterStart | Health check registration, service discovery |
300
+ | BeforeStop | Connection drain, state persistence |
301
+ | AfterStop | Cleanup, metrics export |
302
+
303
+ ---
304
+
305
+ ## Task Dependency Handling
306
+
307
+ For initialization tasks with dependencies:
308
+
309
+ ### Processor Interface
310
+
311
+ ```go
312
+ type processor interface {
313
+ // IsInit: Check if initialization needed
314
+ IsInit() bool
315
+
316
+ // Apply: Execute initialization
317
+ Apply(seeds []interface{}) error
318
+
319
+ // LoadSeeds: Get initialization data
320
+ LoadSeeds() ([]interface{}, error)
321
+
322
+ // GetJobID: Task sequence number
323
+ GetJobID() int
324
+
325
+ // GetDepends: Dependencies (job IDs)
326
+ GetDepends() []int
327
+ }
328
+ ```
329
+
330
+ ### Example: Database Initialization
331
+
332
+ ```go
333
+ type DatabaseInit struct {
334
+ jobID int
335
+ depends []int
336
+ }
337
+
338
+ func (d *DatabaseInit) GetJobID() int { return d.jobID }
339
+ func (d *DatabaseInit) GetDepends() []int { return d.depends }
340
+ func (d *DatabaseInit) IsInit() bool {
341
+ // Check if tables exist
342
+ return !d.tablesExist()
343
+ }
344
+ func (d *DatabaseInit) LoadSeeds() ([]interface{}, error) {
345
+ // Load seed data from files
346
+ return d.loadSeedData(), nil
347
+ }
348
+ func (d *DatabaseInit) Apply(seeds []interface{}) error {
349
+ // Create tables and insert seeds
350
+ return d.createTablesAndInsert(seeds)
351
+ }
352
+ ```
353
+
354
+ ### Task Ordering
355
+
356
+ Sort processors by dependencies:
357
+
358
+ ```go
359
+ func runInitialization(processors []processor) error {
360
+ // Sort by dependencies (topological order)
361
+ sort.Slice(processors, func(i, j int) bool {
362
+ return processors[i].GetJobID() < processors[j].GetJobID()
363
+ })
364
+
365
+ for _, p := range processors {
366
+ if p.IsInit() {
367
+ seeds, err := p.LoadSeeds()
368
+ if err != nil {
369
+ return err
370
+ }
371
+ if err := p.Apply(seeds); err != nil {
372
+ return err
373
+ }
374
+ }
375
+ }
376
+ return nil
377
+ }
378
+ ```
379
+
380
+ ---
381
+
382
+ ## Environment Variable Integration
383
+
384
+ Combine file config with environment overrides:
385
+
386
+ ```go
387
+ c := config.New(
388
+ config.WithSource(
389
+ file.NewSource("configs"),
390
+ // Add env source
391
+ env.NewSource("APP_"), // APP_SERVER_HTTP_ADDR → server.http.addr
392
+ ),
393
+ )
394
+ ```
395
+
396
+ Environment variables override file values:
397
+ ```bash
398
+ APP_SERVER_HTTP_ADDR=0.0.0.0:9000 # Overrides config.yaml
399
+ ```