yjcli 0.1.4__tar.gz → 0.2.0__tar.gz

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 (55) hide show
  1. {yjcli-0.1.4 → yjcli-0.2.0}/PKG-INFO +4 -2
  2. {yjcli-0.1.4 → yjcli-0.2.0}/README.md +3 -1
  3. {yjcli-0.1.4 → yjcli-0.2.0}/pyproject.toml +1 -1
  4. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/skills/yj-arch-core/SKILL.md +3 -1
  5. yjcli-0.2.0/src/yjcli/data/skills/yj-scheduler/SKILL.md +124 -0
  6. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/AGENTS.md +1 -0
  7. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/modules/constants.py +2 -0
  8. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/services/scaffold.py +1 -1
  9. {yjcli-0.1.4 → yjcli-0.2.0}/.gitignore +0 -0
  10. {yjcli-0.1.4 → yjcli-0.2.0}/LICENSE +0 -0
  11. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/__init__.py +0 -0
  12. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/__main__.py +0 -0
  13. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/cli.py +0 -0
  14. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/commands/__init__.py +0 -0
  15. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/commands/init_cmd.py +0 -0
  16. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/commands/platform.py +0 -0
  17. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/commands/service.py +0 -0
  18. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/commands/sync.py +0 -0
  19. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/__init__.py +0 -0
  20. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/skills/yj-backend-msa/SKILL.md +0 -0
  21. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/skills/yj-backend-service/SKILL.md +0 -0
  22. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/skills/yj-browser-extension/SKILL.md +0 -0
  23. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/skills/yj-cli/SKILL.md +0 -0
  24. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/skills/yj-frontend/SKILL.md +0 -0
  25. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/skills/yj-mobile-app/SKILL.md +0 -0
  26. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/skills/yj-pc-app/SKILL.md +0 -0
  27. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/.gitignore +0 -0
  28. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/Makefile +0 -0
  29. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/TOOLS.md +0 -0
  30. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/make.bat +0 -0
  31. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/platform/envs/app/.env.development +0 -0
  32. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/platform/envs/app/.env.examples +0 -0
  33. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/platform/envs/app/.env.local-dev +0 -0
  34. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/platform/envs/app/.env.production +0 -0
  35. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/platform/envs/listen/.env.development +0 -0
  36. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/platform/envs/listen/.env.examples +0 -0
  37. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/platform/envs/listen/.env.local-dev +0 -0
  38. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/platform/envs/listen/.env.production +0 -0
  39. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/platform/envs/worker/.env.development +0 -0
  40. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/platform/envs/worker/.env.examples +0 -0
  41. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/platform/envs/worker/.env.local-dev +0 -0
  42. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/platform/envs/worker/.env.production +0 -0
  43. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/platform/frontend/package.json +0 -0
  44. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/platform/frontend/vite.config.ts +0 -0
  45. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/platform/scripts/run.bat +0 -0
  46. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/platform/scripts/run.sh +0 -0
  47. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/data/templates/settings.json +0 -0
  48. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/modules/__init__.py +0 -0
  49. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/modules/fsutil.py +0 -0
  50. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/modules/paths.py +0 -0
  51. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/modules/prompt.py +0 -0
  52. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/services/__init__.py +0 -0
  53. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/services/status.py +0 -0
  54. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/services/sync.py +0 -0
  55. {yjcli-0.1.4 → yjcli-0.2.0}/src/yjcli/services/wiring.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: yjcli
3
- Version: 0.1.4
3
+ Version: 0.2.0
4
4
  Summary: Scaffold platforms, services, and AI agent wiring (Cursor/Claude/Codex) for YJ architecture repos.
5
5
  Project-URL: Homepage, https://github.com/yseiren87/yjcli
6
6
  Project-URL: Repository, https://github.com/yseiren87/yjcli
@@ -68,7 +68,7 @@ make backend NAME=api # start one service
68
68
 
69
69
  Use with `-t` / `--type` (repeatable on `init` / `platform add`):
70
70
 
71
- `backend` · `backend-service` · `frontend` · `mobile-app` · `pc-app` · `cli` · `browser-extension`
71
+ `backend` · `backend-service` · `frontend` · `mobile-app` · `pc-app` · `cli` · `browser-extension` · `scheduler`
72
72
 
73
73
  ## What `init` creates
74
74
 
@@ -146,9 +146,11 @@ yjcli init --force
146
146
  yjcli platform add
147
147
  yjcli platform add --all
148
148
  yjcli platform add -t cli
149
+ yjcli platform add -t scheduler
149
150
 
150
151
  yjcli service add
151
152
  yjcli service add -p backend -n api
153
+ yjcli service add -p scheduler -n operations
152
154
 
153
155
  yjcli sync agents
154
156
  yjcli sync skills
@@ -43,7 +43,7 @@ make backend NAME=api # start one service
43
43
 
44
44
  Use with `-t` / `--type` (repeatable on `init` / `platform add`):
45
45
 
46
- `backend` · `backend-service` · `frontend` · `mobile-app` · `pc-app` · `cli` · `browser-extension`
46
+ `backend` · `backend-service` · `frontend` · `mobile-app` · `pc-app` · `cli` · `browser-extension` · `scheduler`
47
47
 
48
48
  ## What `init` creates
49
49
 
@@ -121,9 +121,11 @@ yjcli init --force
121
121
  yjcli platform add
122
122
  yjcli platform add --all
123
123
  yjcli platform add -t cli
124
+ yjcli platform add -t scheduler
124
125
 
125
126
  yjcli service add
126
127
  yjcli service add -p backend -n api
128
+ yjcli service add -p scheduler -n operations
127
129
 
128
130
  yjcli sync agents
129
131
  yjcli sync skills
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "yjcli"
3
- version = "0.1.4"
3
+ version = "0.2.0"
4
4
  description = "Scaffold platforms, services, and AI agent wiring (Cursor/Claude/Codex) for YJ architecture repos."
5
5
  readme = "README.md"
6
6
  requires-python = ">=3.12"
@@ -30,6 +30,7 @@ mobile-app/ # yj-mobile-app
30
30
  pc-app/ # yj-pc-app
31
31
  cli/ # yj-cli
32
32
  browser-extension/ # yj-browser-extension
33
+ scheduler/ # yj-scheduler
33
34
  ```
34
35
 
35
36
  ```text
@@ -64,7 +65,7 @@ Required files at each service root (no plain `.env`):
64
65
  `.env.local` convention unless a thin loader maps it to this structure.
65
66
  - Env field sets come from `templates/platform/envs/<kind>/` via platform mapping (`listen` / `worker` / `app`).
66
67
  - `listen`: `backend` (PORT 8080), `frontend` (PORT 5173)
67
- - `worker`: `backend-service`, `browser-extension/native_*` (HOST/PORT optional)
68
+ - `worker`: `backend-service`, `browser-extension/native_*`, `scheduler` (HOST/PORT optional)
68
69
  - `app`: `cli`, `mobile-app`, `pc-app`, `browser-extension` (NAME/VERSION only)
69
70
  Do not invent fields outside those templates; environment filenames remain
70
71
  extensible through the `.env.<environment>` pattern above.
@@ -93,6 +94,7 @@ Required files at each service root (no plain `.env`):
93
94
  | `cli/**` | `yj-cli` |
94
95
  | `browser-extension/native_*/**` | `yj-backend-service` |
95
96
  | `browser-extension/**` (other) | `yj-browser-extension` |
97
+ | `scheduler/**` | `yj-scheduler` |
96
98
 
97
99
  Never load all platform skills. Never apply a platform skill outside its folder.
98
100
 
@@ -0,0 +1,124 @@
1
+ ---
2
+ name: yj-scheduler
3
+ description: >-
4
+ Long-running scheduler architecture for multiple periodic batch jobs. Use
5
+ only when editing scheduler/**. Language-agnostic: use an established
6
+ scheduling framework from the project's ecosystem without prescribing a
7
+ specific library. Covers job registration, execution isolation, overlap,
8
+ misfires, timezones, retries, locks, observability, and graceful shutdown.
9
+ Do not use for backend/, backend-service/, frontend/, mobile-app/, pc-app/,
10
+ cli/, or browser-extension/.
11
+ ---
12
+
13
+ # yj-scheduler
14
+
15
+ Requires `yj-arch-core`. Scope: **`scheduler/` only**.
16
+
17
+ ## Purpose
18
+
19
+ Run multiple recurring batch jobs in one or more long-running scheduler
20
+ processes. Use an established scheduling framework from the selected language
21
+ ecosystem. Choose the concrete framework from the repository's stack and
22
+ existing dependencies.
23
+
24
+ Do not implement cron parsing, durable scheduling, misfire handling, or a
25
+ `while` + `sleep` scheduling loop from scratch.
26
+
27
+ ## Shape
28
+
29
+ ```text
30
+ scheduler/
31
+ scripts/ # platform-level only
32
+ {scheduler_name}/ # one deployable scheduler process
33
+ apps/ # entry: boot, registration, wiring, shutdown
34
+ services/
35
+ {job_name}/ # one batch workflow
36
+ domains/ # optional: owned concepts only
37
+ modules/ # scheduler adapter, db/api clients, lock, clock
38
+ ```
39
+
40
+ - One scheduler process may register multiple related jobs.
41
+ - Split jobs into separate `{scheduler_name}` deployables only when they need
42
+ independent deployment, scaling, dependencies, permissions, or failure isolation.
43
+ - Do not add per-job `scripts/` or Makefiles. Root `make scheduler` runs all
44
+ scheduler services; `NAME=<scheduler_name>` runs one.
45
+ - This is a long-running worker platform. `HOST` and `PORT` are optional and
46
+ should exist only when the process exposes a real endpoint.
47
+
48
+ ## Roles
49
+
50
+ ### entry (`apps`)
51
+
52
+ - Create and configure the scheduling framework, register triggers, wire job
53
+ handlers, start the process, and perform graceful shutdown.
54
+ - Keep registration declarative and discoverable in one entry area.
55
+ - Framework callbacks must be thin: add execution context, call one flow, and
56
+ report its result. No query, transformation, or persistence logic in callbacks.
57
+
58
+ ### flow (`services/{job_name}`)
59
+
60
+ - Each periodic job is an independently testable workflow.
61
+ - Own job-specific input, orchestration, batching, checkpointing, and result shape.
62
+ - A failure in one job must not terminate or block unrelated jobs.
63
+ - Make operations idempotent whenever a retry or duplicate trigger is possible.
64
+
65
+ ### domain / infra
66
+
67
+ - Add `domains/` only for concepts or shared policy owned by this process;
68
+ persistence is not required. Do not create a domain merely because a job exists.
69
+ - Put framework integration, distributed locks, clocks, persistence, logging,
70
+ and external clients in `modules/`.
71
+ - Do not import another platform's source tree; communicate through explicit
72
+ APIs or generated contracts.
73
+
74
+ ## Scheduling policy
75
+
76
+ For every job, make these decisions explicit near its registration or config:
77
+
78
+ - stable job identifier and handler
79
+ - periodic or calendar trigger and explicit timezone
80
+ - whether overlapping executions are allowed
81
+ - misfire behavior (skip, coalesce, or catch up)
82
+ - timeout, retry, and backoff behavior
83
+ - concurrency limit and multi-instance ownership/locking strategy
84
+
85
+ Never rely implicitly on the host's local timezone. Do not scatter schedule
86
+ expressions across callbacks. Fixed business schedules may live in typed code or
87
+ project configuration; expose them as environment-specific settings only when
88
+ deployments genuinely need different schedules.
89
+
90
+ When more than one scheduler instance can run, use the framework's persistent
91
+ job store/single-run facility or a distributed lock. A process-local mutex does
92
+ not prevent duplicate execution across instances.
93
+
94
+ ## Reliability and observability
95
+
96
+ - Log job id, execution/run id, scheduled time, actual start, completion or
97
+ failure, duration, and retry attempt using structured fields.
98
+ - Define shutdown behavior: stop accepting triggers, then finish or safely
99
+ cancel active jobs within a bounded grace period.
100
+ - Long-running or high-volume jobs should use bounded batches and checkpoints so
101
+ they can resume safely after interruption.
102
+ - Keep retry scope narrow. Do not retry permanent validation or authorization
103
+ failures as though they were transient infrastructure failures.
104
+ - Inject or wrap the clock in flow/domain tests; do not make business rules
105
+ depend directly on wall-clock calls throughout the codebase.
106
+
107
+ ## Import direction
108
+
109
+ ```text
110
+ entry/framework callback -> flow -> domain? -> infra
111
+ entry -> infra
112
+ flow -> infra
113
+ ```
114
+
115
+ Forbidden: business logic in trigger callbacks; flow importing entry/framework
116
+ bootstrap; domain importing scheduler framework types; jobs calling one another
117
+ for sequencing when a single coordinating flow owns the workflow.
118
+
119
+ ## Editing scope
120
+
121
+ - Stay within `scheduler/{scheduler_name}/` unless the task explicitly changes
122
+ shared contracts or platform wiring.
123
+ - Prefer extending an existing scheduler process for related jobs; do not create
124
+ one deployable per cron expression automatically.
@@ -29,6 +29,7 @@ When creating, modifying, reviewing, or refactoring code:
29
29
  | `cli/**` | `yj-cli` |
30
30
  | `browser-extension/native_*/**` | `yj-backend-service` |
31
31
  | `browser-extension/**` (other) | `yj-browser-extension` |
32
+ | `scheduler/**` | `yj-scheduler` |
32
33
 
33
34
  Never load all platform skills. Never apply a platform skill outside its folder.
34
35
 
@@ -10,6 +10,7 @@ PLATFORMS: tuple[str, ...] = (
10
10
  "pc-app",
11
11
  "cli",
12
12
  "browser-extension",
13
+ "scheduler",
13
14
  )
14
15
 
15
16
  RESERVED_SERVICE_NAMES: frozenset[str] = frozenset({"scripts", "proto"})
@@ -26,4 +27,5 @@ PLATFORM_ENV: dict[str, tuple[str, dict[str, str]]] = {
26
27
  "mobile-app": ("app", {}),
27
28
  "pc-app": ("app", {}),
28
29
  "browser-extension": ("app", {}),
30
+ "scheduler": ("worker", {}),
29
31
  }
@@ -122,7 +122,7 @@ def create_service(root: Path, platform: str, name: str) -> None:
122
122
  _copy_env_templates(platform, name, base)
123
123
  _copy_platform_extras(platform, name, base)
124
124
 
125
- if platform in {"backend", "backend-service"}:
125
+ if platform in {"backend", "backend-service", "scheduler"}:
126
126
  for sub in ("apps", "services", "domains", "modules"):
127
127
  (base / sub).mkdir(exist_ok=True)
128
128
  elif platform == "frontend":
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes