You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: .agents/skills/agent-core-dev/orient.md
+2-2Lines changed: 2 additions & 2 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -68,10 +68,10 @@ There is no domain-layer numbering — a domain may import any other domain, gui
68
68
69
69
## Comment convention
70
70
71
-
`packages/agent-core-v2/AGENTS.md` bans comments: no file headers, no section banners, no statement-level narration— the code is the source of truth. The only exception is JSDoc attached to exported symbols, which flows into the generated `.d.ts` and the consumers' IDE hover. Tooling directives (`eslint-disable`, `@ts-expect-error`, …) are banned too: fix the underlying lint/type problem instead, and put negative type-safety cases in compiler-asserted fixtures. DI scope is carried by registration: `LifecycleScope.App`, `LifecycleScope.Session`, or `LifecycleScope.Agent`. A `workspace*` filename marks workspace-domain ownership, not a DI scope (see service-authoring.md).
71
+
`packages/agent-core-v2/AGENTS.md` bans comments entirely: no file headers, no section banners, no statement-level narration, no JSDoc (not even on exported symbols) — the code is the source of truth. The only exception is a load-bearing lint-suppression directive (`oxlint-disable` / `eslint-disable`) for a deliberate pattern; other tooling directives (`@ts-expect-error`, …) are banned: fix the underlying lint/type problem instead, and put negative type-safety cases in compiler-asserted fixtures. DI scope is carried by registration: `LifecycleScope.App`, `LifecycleScope.Session`, or `LifecycleScope.Agent`. A `workspace*` filename marks workspace-domain ownership, not a DI scope (see service-authoring.md).
72
72
73
73
## Red lines (this stage)
74
74
75
75
- Import via the `#/...` alias (mapped to `src/`); never reach into another domain's internals by relative path.
76
76
- Short-lived may inject long-lived; never the reverse.
77
-
- No comments — not file headers, not beside statements; exported-symbol JSDoc is the only exception.
77
+
- No comments — not file headers, not beside statements, not JSDoc; a load-bearing lint-suppression directive is the only exception.
Copy file name to clipboardExpand all lines: .agents/skills/agent-core-dev/service-authoring.md
+2-3Lines changed: 2 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -164,7 +164,7 @@ What belongs here:
164
164
-**Helper classes / functions** used only by this impl (e.g. a built-in writer, an `extractError` helper) — co-located in the same file.
165
165
-**Top-level `registerScopedService(...)`** — one per Service the file owns; importing the impl file runs the registration.
166
166
167
-
Base class: extend `Service` (from `#/_base/di/service`) when the unit needs capability calls on `this` — `provide` / `effect` / `on` / `get` / `ref` (e.g. contributing a record to a `collection` token). `Service` extends `Disposable`, so `_register` keeps working; constructor-time `provide` / `on` / `effect` calls are buffered and flushed by the kernel after construction, while `get` / `ref` throw inside the constructor (dependencies stay constructor parameters). Otherwise extend `Disposable` — both are full DI units; a service whose own members collide with the `Service` vocabulary (`name` / `state` / `config` / `get`) must stay on `Disposable` (leave a NOTE comment saying so).
167
+
Base class: extend `Service` (from `#/_base/di/service`) when the unit needs capability calls on `this` — `provide` / `effect` / `on` / `get` / `ref` (e.g. contributing a record to a `collection` token). `Service` extends `Disposable`, so `_register` keeps working; constructor-time `provide` / `on` / `effect` calls are buffered and flushed by the kernel after construction, while `get` / `ref` throw inside the constructor (dependencies stay constructor parameters). Otherwise extend `Disposable` — both are full DI units; a service whose own members collide with the `Service` vocabulary (`name` / `state` / `config` / `get`) must stay on `Disposable`.
168
168
169
169
## Constructor conventions
170
170
@@ -296,9 +296,8 @@ Importing the package therefore fires every `register*` side effect, exactly as
296
296
297
297
## Comments
298
298
299
-
-**No comments** (orient.md): no file headers, no statement-level narration; the only exception is JSDoc attached to exported symbols.
299
+
-**No comments** (orient.md): no file headers, no statement-level narration, no JSDoc; the only exception is a load-bearing lint-suppression directive.
300
300
-**Methods and fields carry no comments by default.** Well-named identifiers and types say *what*; the code is the source of truth for *how*.
301
-
- Write an inline comment only when the *why* is non-obvious (a hidden constraint, a subtle invariant, a workaround). One short line.
302
301
- For unimplemented stubs, throw `NotImplementedError('feature')` rather than `throw new Error('TODO: …')` (errors.md).
Copy file name to clipboardExpand all lines: .agents/skills/agent-core-dev/test.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -21,7 +21,7 @@ Resolving by interface is what makes `registerScopedService(ISut, Sut, …)` par
21
21
22
22
Pure functions, value objects, and services with **no**`@IService` dependencies may be constructed directly.
23
23
24
-
The only other exception is a test that genuinely needs **two independent instances** of the same service with different dependencies (e.g. constructing two `TurnService`s with different `ILoopRunner`s). A singleton-per-container resolution cannot produce both, so `ix.createInstance(Impl)` is acceptable there — annotate it with a comment explaining why.
24
+
The only other exception is a test that genuinely needs **two independent instances** of the same service with different dependencies (e.g. constructing two `TurnService`s with different `ILoopRunner`s). A singleton-per-container resolution cannot produce both, so `ix.createInstance(Impl)` is acceptable there — state the reason in the test name and local identifiers.
Copy file name to clipboardExpand all lines: .agents/skills/agent-core-dev/verify.md
+1-1Lines changed: 1 addition & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -21,7 +21,7 @@ Walk the stages you touched and confirm:
21
21
-**Design** — scope follows state identity; no `Map<sessionId, …>` at `App`; dependency arrows do not make a foundational layer know an upstream one; no cycle was routed around.
22
22
-**Implement** — no `new` on `@IService`-carrying classes; `@IX` on constructor params only (service params after static params); interface + impl carry `_serviceBrand`; decorator names unique; coded errors only; flags for unreleased behavior.
23
23
-**Test** — SUT resolved by interface; stubs under `test/`; scope tests re-register after `_clearScopedRegistryForTests()`; teardown through one `DisposableStore`.
24
-
-**Files** — no comments (exported-symbol JSDoc excepted); registration runs from the impl file's top level; the new domain is exported from `src/index.ts`.
24
+
-**Files** — no comments (no JSDoc either); registration runs from the impl file's top level; the new domain is exported from `src/index.ts`.
25
25
26
26
Then re-read the [global red lines](SKILL.md#global-red-lines) once — they catch most cross-stage mistakes in a single scan.
non-private, non-ignored workspace packages — in practice **`@pythoughts/pythinker-code`** and the
35
-
SDK-adjacent packages not on the ignore list. When adding a workspace package, decide its ignore/
36
-
publish status explicitly, and remember `flake.nix` workspace lists must be updated by hand
37
-
(root `AGENTS.md`).
31
+
`@pymodel/pythinker-code` is the public npm package. Desktop and VS Code package files are private;
32
+
their versions are release signals but changesets does not publish them to npm. When adding a
33
+
workspace, set its `private` and changesets policy explicitly and update `flake.nix`.
38
34
39
35
## release.yml job map
40
36
41
37
| Job | Trigger | Notes |
42
38
|---|---|---|
43
-
|`Release`| every main push | install → build catalog → `pnpm build` → changesets action |
44
-
|`Redeploy code.pythinker.com`|`packages_published == 'true'`| runs `scripts/release/verify-release-consistency.mjs`, then POSTs `DOKPLOY_CDN_DEPLOY_WEBHOOK` (skips with a warning if the secret is unset) |
45
-
|`Update Homebrew tap`| published |`scripts/release/update-brew-formula.mjs` with `TAP_GITHUB_TOKEN` (skips if unset) |
46
-
|`Deploy docs`| published | reusable `docs-deploy.yml`|
|`Redeploy CDN` + verify | native assets published | Webhook may retry; verification is the hard gate |
46
+
|`Update Homebrew tap`| CLI was published | App token scoped to `homebrew-tap` contents |
47
+
|`Release lane summary`| always | One table with provenance state; fails when an expected enabled lane failed or skipped |
49
48
50
-
`pythinker_native_release` and the release tag come from
51
-
`apps/pythinker-code/scripts/native/resolve-release.mjs`, driven by the changesets action's
52
-
`publishedPackages` output; the tag format is `@pythoughts/pythinker-code@<version>`.
49
+
Set `RELEASE_LANE_DESKTOP`, `RELEASE_LANE_VSCODE`, `RELEASE_LANE_CDN`, or
50
+
`RELEASE_LANE_BREW` to exactly `disabled` for a conscious temporary opt-out. Missing credentials are
51
+
otherwise errors.
53
52
54
53
## Failure modes and known lessons
55
54
@@ -61,28 +60,42 @@ publish status explicitly, and remember `flake.nix` workspace lists must be upda
61
60
genuinely half-published release — read the log; do not blind-rerun.
62
61
-**Version PR looks wrong.** Never patch the `changeset-release/main` branch by hand. Fix or add
63
62
changesets on `main`; the next workflow run regenerates the PR.
64
-
-**Native builder fails after npm publish succeeded.** npm state is final; native jobs are
65
-
re-runnable against the same workflow run (`gh run rerun <id> --failed`). `--clobber` on asset
66
-
upload makes re-runs safe.
63
+
-**Beta or Nightly checks Stable.** GitHub does not infer update channels. Confirm the release is a
64
+
prerelease and contains `beta*.yml` or `nightly*.yml`; do not rename Stable manifests.
65
+
-**Native builder fails after npm publish succeeded.** npm state is final. Re-run failed jobs from
66
+
the same run before any assets upload. A complete asset set is an idempotent no-op. A partial set
67
+
must not be filled from a rebuild; keep it or publish a new patch version.
67
68
-**CDN not updated after publish.**`verify-release-consistency.mjs` gates the webhook: local
68
69
`apps/pythinker-code/package.json` version must equal the npm `latest` dist-tag (plus sane
69
70
`beta`/`dev` tags). A mismatch means the checkout in the job predates the release commit or npm
70
-
propagation lag — check `npm view @pythoughts/pythinker-code dist-tags` before touching anything.
71
+
propagation lag — check `npm view @pymodel/pythinker-code dist-tags` before touching anything.
71
72
Dokploy deploy specifics: see memory `cdn-dokploy-deploy-pipeline`.
72
73
-**`pnpm install` fails in CI or locally.**`engine-strict=true` + Node `>=24.15.0` — check
73
74
`.nvmrc` before debugging anything else.
74
75
-**Pre-push hook** (`scripts/pre-push.sh` via simple-git-hooks) gates local pushes; a hook failure
75
76
is a real gate failure — fix the cause, never `--no-verify`.
76
77
78
+
## Recovery
79
+
80
+
| Symptom | Command | Safety |
81
+
|---|---|---|
82
+
| Desktop tag job failed |`git tag desktop-v<VERSION> <RELEASE_SHA> && git push origin desktop-v<VERSION>`| Confirm the tag does not exist first; pushing it starts a public release workflow |
83
+
| VS Code lane partially failed |`gh workflow run vscode-release.yml --ref <RELEASE_SHA> -f expected-version=<VERSION>`| Version is checked; both publishers skip versions already present |
84
+
| Native matrix failed before upload |`gh run rerun <RUN_ID> --failed`| Reuses the same run and commit; do not mix a rebuilt partial asset set |
85
+
| CDN is stale | Re-run the failed `Redeploy CDN` or verification job | Do not republish npm; nightly reconciliation remains red until aligned |
86
+
| Unknown lane drift |`pnpm release:status`| Read-only; queries npm, GitHub Releases, CDN, Marketplace, and Open VSX |
87
+
77
88
## Verification commands
78
89
79
90
```bash
80
91
gh run list --workflow=release.yml --branch=main -L 3 # workflow health
92
+
gh run list --workflow=nightly.yml --branch=main -L 3 # Nightly desktop health
81
93
gh pr list --search 'ci: release packages in:title' --state open
82
-
npm view @pythoughts/pythinker-code version # published version
-Active tab: `chalk.bgHex(colors.selectionBg).hex(colors.inverseText).bold(\` ${label} \`)`; inactive tab: `chalk.hex(colors.textMuted)`. Both have the same visible width.
0 commit comments