发布 v0.8.3
This commit is contained in:
+1
-1
@@ -1 +1 @@
|
|||||||
0.6.7
|
0.6.10
|
||||||
@@ -0,0 +1,132 @@
|
|||||||
|
# Auth Login Methods(登录方式接入契约)
|
||||||
|
|
||||||
|
> 面板现有登录方式:密码(+可选 TOTP)、OIDC / GitHub(OAuth)、通行密钥(Passkey / WebAuthn)、Web3 钱包(EIP-4361)。
|
||||||
|
> 新增或修改任何登录方式时,以下契约是安全红线,缺一不可。
|
||||||
|
|
||||||
|
## 1. 登录守卫(防爆破)
|
||||||
|
|
||||||
|
公开登录端点的失败必须计入 `loginGuard`:`guardKey(clientIP, <账号标识>)`,账号未知用固定占位名(如 passkey 的 `__passkey__`),已知用其标识(如钱包地址小写)。锁定检查在校验之前;失败经 `auth.failLogin`(自带阈值转锁定与告警推送),成功 `guard.success`。阈值/时长取安全设置,不硬编码。
|
||||||
|
|
||||||
|
## 2. 系统日志留痕
|
||||||
|
|
||||||
|
公开登录端点不经系统日志中间件,handler 必须显式 `logs.Record` 成败(参考 `authHandler.recordLogin` / `passkeyHandler.recordLogin` / `walletHandler.recordWallet`);登录失败是安全关键事件,不允许无痕。JWT 组内的绑定/解绑由中间件自动留痕,无需额外埋点。
|
||||||
|
|
||||||
|
## 3. 令牌版本(TokenVersion)
|
||||||
|
|
||||||
|
绑定、解绑、凭据及认证因子变更均属敏感变更:必须在事务内
|
||||||
|
`bumpTokenVersionTx`(或 `RevokeSessions`)使旧 JWT 失效,并按第 6 节携带
|
||||||
|
`TokenProof`、接续操作者会话。因子写入与版本递增不得拆成两个独立提交。
|
||||||
|
|
||||||
|
## 4. 「至少一种登录方式」不变量
|
||||||
|
|
||||||
|
密码登录禁用要求至少一种在当前 `EffectiveAppURL` 下**可实际登录**的免密方式
|
||||||
|
(`usablePasswordlessTx`);地址为空时 Passkey、钱包和 OAuth 均不可用。禁用期间移除
|
||||||
|
最后一种免密方式被拒:解绑身份走 `ensureNotLastLogin`,删通行密钥走对称检查。
|
||||||
|
这些检查都在事务内先 `lockUserForAuthChange` 锁用户行,防并发绕过。新登录方式要
|
||||||
|
明确决策如何参与该不变量:
|
||||||
|
|
||||||
|
- **复用 `UserIdentity` 表**(如钱包,provider+subject 唯一)→ 走 `identityCountTx` 自动参与,零改动;
|
||||||
|
- **独立表**(如 Passkey 的 `UserPasskey`)→ 参照 `passkeyCountTx` 增加计数入口,并在开启门槛(`hasAnyPasswordless`)与两个 `ensureNot*` 检查里对称接入;api 层把 `ErrLastIdentity` 映射 409。
|
||||||
|
|
||||||
|
## 5. 挑战/状态的一次性消费
|
||||||
|
|
||||||
|
挑战-响应类流程(OAuth state、WebAuthn challenge、SIWE nonce)一律进程内 `map + mutex + TTL + gc`,取用即删(参考 `oauthPending` / `passkeyPending` / `walletPending`);不落库、不引 Redis。TTL 5-10 分钟。
|
||||||
|
|
||||||
|
## 6. 场景:已鉴权敏感事务的提交屏障
|
||||||
|
|
||||||
|
### 1. Scope / Trigger
|
||||||
|
|
||||||
|
凡请求先通过 JWT 中间件、随后仍会读取 body、等待外部回调或写入认证/安全配置,
|
||||||
|
都必须防止请求处理期间的 Logout、定点撤销或撤销全部会话被旧请求绕过。
|
||||||
|
|
||||||
|
### 2. Signatures
|
||||||
|
|
||||||
|
```go
|
||||||
|
type TokenProof struct {
|
||||||
|
Ver uint
|
||||||
|
Jti string
|
||||||
|
}
|
||||||
|
|
||||||
|
func tokenProofOf(c *gin.Context) service.TokenProof
|
||||||
|
func (s *AuthService) ensureTokenCurrentTx(
|
||||||
|
tx *gorm.DB, user *model.User, proof TokenProof,
|
||||||
|
) error
|
||||||
|
func (s *AuthService) RenewToken(
|
||||||
|
ctx context.Context, username, oldToken string, meta SessionMeta,
|
||||||
|
) (string, time.Time, error)
|
||||||
|
```
|
||||||
|
|
||||||
|
持久化契约使用 `user_sessions.token_id` 表示逻辑会话;敏感换发不改变该 JTI。
|
||||||
|
|
||||||
|
### 3. Contracts
|
||||||
|
|
||||||
|
- `RequireAuth` 必须把本次请求实际观察到的 `TokenVersion + JTI` 写入 Context,
|
||||||
|
Handler 不得事后只按用户名读取“最新版本”代替 proof。
|
||||||
|
- 敏感事务、`RevokeSession` 与 Logout 的数据库路径统一先锁用户行,再检查/更新
|
||||||
|
会话行;持锁后调用 `ensureTokenCurrentTx`。
|
||||||
|
- proof 通过后,认证因子写入、版本递增及事务内换发必须同成同败。需要在 Handler
|
||||||
|
末尾换发的旧接口,`RenewToken` 也须重新锁用户并确认当前版本恰为
|
||||||
|
`oldClaims.Ver + 1`。
|
||||||
|
- 换发沿用旧 JWT 的合法 JTI;有旧会话行时只接续未撤销行,存在但已撤销或更新
|
||||||
|
失败必须关闭。兼容期无行 Token 可建行,但仍沿用旧 JTI,因此 Logout 的
|
||||||
|
tombstone 能同时撤销换发前后的 JWT。
|
||||||
|
- Logout 持久撤销须按 JTI 会话行解析稳定的 `user_id`,不得只按旧 JWT 的可变
|
||||||
|
username/subject 找用户;JTI tombstone 至少保留“旧 JWT 剩余寿命 +
|
||||||
|
一个完整 `tokenTTL`”,兜住 legacy 无行换发、改名提交和持久化撤销之间的
|
||||||
|
窄窗口。
|
||||||
|
- 外部身份登录须在用户锁内重查身份仍绑定;OAuth 登录还须在最终签发事务内重查
|
||||||
|
Provider 当前可用。
|
||||||
|
- proof 不二次检查自然到期:请求在 JWT 未过期时通过中间件即取得本次请求的认证
|
||||||
|
边界;不得为此额外引入长事务、分布式锁或持久状态机。
|
||||||
|
|
||||||
|
### 4. Validation & Error Matrix
|
||||||
|
|
||||||
|
| 条件 | 结果 |
|
||||||
|
| --- | --- |
|
||||||
|
| `user.TokenVersion != proof.Ver` | `ErrTokenStale` → HTTP 401 |
|
||||||
|
| JTI tombstone 命中或会话行已撤销 | `ErrTokenStale` → HTTP 401 |
|
||||||
|
| 旧会话行存在但接续命中 0 行 | 失败关闭,不得 fallback 创建 |
|
||||||
|
| 已验签当前版本的兼容 Token 确无会话行 | 沿用原 JTI 创建会话行 |
|
||||||
|
| 改名后用换发前 JWT Logout | 按 JTI/user_id 撤销新旧 JWT;旧 subject 不参与归属 |
|
||||||
|
| Handler 分段换发时版本不是 `oldVer + 1` | `ErrTokenStale`,前端重新登录 |
|
||||||
|
| 登录签发前身份已解绑 / Provider 已不可用 | 拒绝登录,不签发 JWT |
|
||||||
|
|
||||||
|
### 5. Good / Base / Bad Cases
|
||||||
|
|
||||||
|
- Good:TOTP 激活事务内依次锁用户、验 proof、写因子、递增版本、沿用 JTI 换发。
|
||||||
|
- Base:无会话行的存量 JWT 可完成一次合法变更,但换发后的 JWT 与旧 JWT 共用
|
||||||
|
JTI,后到 Logout 可同时撤销。
|
||||||
|
- Bad:proof 普通查询通过后释放锁,定点撤销完成,再把旧行更新失败当“无行”创建
|
||||||
|
新会话;这会复活已撤销 Token。
|
||||||
|
|
||||||
|
### 6. Tests Required
|
||||||
|
|
||||||
|
- TOTP 激活 × 撤销全部:旧 proof 返回 `ErrTokenStale`,因子与版本均不改变。
|
||||||
|
- proof check → 定点撤销 → renew:撤销后的行不得被新建替代。
|
||||||
|
- recorded 与 legacy 无行会话各测一次“改名后 old-token Logout”:换发 JWT
|
||||||
|
必须随同失效;recorded 行写入 `revoked_at`,legacy tombstone 覆盖 fresh expiry。
|
||||||
|
- OAuth/钱包登录在最终事务前删除身份:不得签发会话;OAuth 禁用同理。
|
||||||
|
- Security/OAuth PATCH 使用已撤销 proof:返回 `ErrTokenStale` 且设置不落库。
|
||||||
|
|
||||||
|
### 7. Wrong vs Correct
|
||||||
|
|
||||||
|
```go
|
||||||
|
// Wrong:只按最新用户状态改因子,随后无条件签最新版本 JWT。
|
||||||
|
saveFactor()
|
||||||
|
bumpTokenVersion()
|
||||||
|
return IssueToken(ctx, username)
|
||||||
|
|
||||||
|
// Correct:请求 proof、因子写入、版本递增和会话接续共享事务与用户锁。
|
||||||
|
return db.Transaction(func(tx *gorm.DB) error {
|
||||||
|
user, err := lockUserForAuthChange(tx, username)
|
||||||
|
if err != nil { return err }
|
||||||
|
if err := auth.ensureTokenCurrentTx(tx, user, proof); err != nil { return err }
|
||||||
|
return changeFactorAndRenewTx(tx, user, oldToken)
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
## 其他约定
|
||||||
|
|
||||||
|
- 面板地址依赖:RP ID / 回调 / SIWE domain 均派生自 `settings.EffectiveAppURL()`,为空时返回引导错误(文案对齐 `ErrOAuthNoAppURL`),不得回退猜测。
|
||||||
|
- 登录失败对外文案统一、不透出内部细节(防探测);错误变量集中定义在对应 service 文件头部。
|
||||||
|
- 新端点全量 swagger 中文注释并重新生成 docs/;providers 公开端点(`/auth/oauth/providers`)按需追加 `<method>Login` 可用性布尔,供登录页渲染入口。
|
||||||
@@ -60,3 +60,7 @@ db.Model(&model.AiChannel{}).
|
|||||||
**Fix**:键值加入 `cred.CompartmentID`(空 = 租户根,天然区分)。
|
**Fix**:键值加入 `cred.CompartmentID`(空 = 租户根,天然区分)。
|
||||||
|
|
||||||
**Prevention**:缓存键必须覆盖影响回源结果的**全部**输入维度(租户、区间、区域、过滤参数);给 Credentials/查询结构体新增会改变结果的字段时,同步检查 `ckey` 调用点;隔离行为写进 `cached_test.go` 的 isolation 用例。
|
**Prevention**:缓存键必须覆盖影响回源结果的**全部**输入维度(租户、区间、区域、过滤参数);给 Credentials/查询结构体新增会改变结果的字段时,同步检查 `ckey` 调用点;隔离行为写进 `cached_test.go` 的 isolation 用例。
|
||||||
|
|
||||||
|
## GORM 列名与 map 更新
|
||||||
|
|
||||||
|
- GORM 默认命名把连续大写按公共缩写拆分:`UserOCID` → `user_oc_id`、`TenancyOCID` → `tenancy_oc_id`(不是 `user_ocid`)。用 `Updates(map[string]any{...})` 写裸列名前先确认真实列名(`schema.Parse` 或查建表 SQL),SQLite 下写错列名报 "no such column" 才暴露,MySQL/PG 同错。零值字段(如清空 `passphrase_enc`)必须走 map 更新,struct 更新会忽略零值。(2026-07-23 activate-api-key 切换签名用户)
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ Gin + GORM + SQLite(纯 Go 驱动 `glebarez/sqlite`,免 CGO;默认与推荐)+ AE
|
|||||||
| [IdP Icon Upload](./idp-icon-upload.md) | IdP 公共图标上传、校验与清理契约 | 已填 |
|
| [IdP Icon Upload](./idp-icon-upload.md) | IdP 公共图标上传、校验与清理契约 | 已填 |
|
||||||
| [Database Guidelines](./database-guidelines.md) | GORM 实战约定与常见坑 | 已填 |
|
| [Database Guidelines](./database-guidelines.md) | GORM 实战约定与常见坑 | 已填 |
|
||||||
| [OCI Audit](./oci-audit.md) | 审计事件双通道数据源、检索语义与预算纪律 | 已填 |
|
| [OCI Audit](./oci-audit.md) | 审计事件双通道数据源、检索语义与预算纪律 | 已填 |
|
||||||
|
| [Auth Login Methods](./auth-login-methods.md) | 登录方式接入契约(守卫/留痕/令牌版本/不变量/一次性挑战) | 已填 |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -20,7 +20,7 @@
|
|||||||
|
|
||||||
## 日志回传链路(logrelay)资源命名与描述纪律
|
## 日志回传链路(logrelay)资源命名与描述纪律
|
||||||
|
|
||||||
- **命名派生**:Topic 前缀、IAM Policy 名、SCH Connector DisplayName 一律由 `relayResourceNames(tenancyOCID)`(见 `internal/oci/logrelay_names.go`)基于 `SHA-256(tenancyOCID)[:4]` 派生 `<8hex>-audit` / `<8hex>-audit-p`。**不得在 `logrelay.go` 里再引入品牌明文**(`oci-portal` / `ociportal` / `logs` 等),否则跨租户恒定字面量会成为 Oracle 内部风控识别「共用同一套 oci-portal」的强指纹;背景与证据分档见调研档案 `docs/oci-sdk-caller-fingerprint.md`。
|
- **命名派生**:Topic 前缀、IAM Policy 名、SCH Connector DisplayName 一律由 `relayResourceNames(tenancyOCID)`(见 `internal/oci/logrelay_names.go`)基于 `SHA-256(tenancyOCID)[:4]` 派生 `<8hex>-audit` / `<8hex>-audit-p`。**不得在 `logrelay.go` 里再引入品牌明文**(`oci-portal` / `ociportal` / `logs` 等),否则跨租户恒定字面量会成为 Oracle 内部风控识别「共用同一套 oci-portal」的强指纹;背景与证据分档见工作区任务归档 `.trellis/tasks/archive/2026-07/07-22-research-oci-caller-info/research/oci-sdk-caller-fingerprint.md`。
|
||||||
- **描述文本**:Topic 与 Policy 的 `Description` 用集中常量 `relayTopicDescNew` / `relayPolicyDescNew`(中性英文),不允许写 `oci-portal 日志回传:...` 等品牌/中文明文;SCH Connector 干脆不设 `Description`,避免恒定文案。
|
- **描述文本**:Topic 与 Policy 的 `Description` 用集中常量 `relayTopicDescNew` / `relayPolicyDescNew`(中性英文),不允许写 `oci-portal 日志回传:...` 等品牌/中文明文;SCH Connector 干脆不设 `Description`,避免恒定文案。
|
||||||
- **向后兼容 legacy 命名**:`findRelayTopic` / `findRelayPolicy` / `findRelayConnector` 支持传入多前缀/多名称,顺序为「新命名 → legacy 命名」;新增查找需求要沿用变参签名,不要单独硬编码 legacy 常量到业务函数里。命中 legacy 资源时,`refreshRelayTopicDesc` / `refreshRelayPolicyDesc` 会尽力刷新描述为中性文案,失败不阻塞主流程(权限/服务限流等场景直接忽略)。
|
- **向后兼容 legacy 命名**:`findRelayTopic` / `findRelayPolicy` / `findRelayConnector` 支持传入多前缀/多名称,顺序为「新命名 → legacy 命名」;新增查找需求要沿用变参签名,不要单独硬编码 legacy 常量到业务函数里。命中 legacy 资源时,`refreshRelayTopicDesc` / `refreshRelayPolicyDesc` 会尽力刷新描述为中性文案,失败不阻塞主流程(权限/服务限流等场景直接忽略)。
|
||||||
- **测试**:命名派生、legacy 常量值、描述中性性由 `logrelay_names_test.go` table-driven 锁定;若必须调整 legacy 常量,先评估是否会让存量租户找不到既有资源导致重复创建。
|
- **测试**:命名派生、legacy 常量值、描述中性性由 `logrelay_names_test.go` table-driven 锁定;若必须调整 legacy 常量,先评估是否会让存量租户找不到既有资源导致重复创建。
|
||||||
|
|||||||
+20
-19
@@ -183,7 +183,7 @@ Complex task: ask the user if you can create a Trellis task and enter the planni
|
|||||||
- 1.0 Create task `[required · once]` (only after task-creation consent)
|
- 1.0 Create task `[required · once]` (only after task-creation consent)
|
||||||
- 1.1 Requirement exploration `[required · repeatable]` (`prd.md`; complex tasks also need `design.md` + `implement.md`)
|
- 1.1 Requirement exploration `[required · repeatable]` (`prd.md`; complex tasks also need `design.md` + `implement.md`)
|
||||||
- 1.2 Research `[optional · repeatable]`
|
- 1.2 Research `[optional · repeatable]`
|
||||||
- 1.3 Configure context `[required · once]` — Claude Code, Cursor, OpenCode, Codex, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Reasonix (sub-agent-dispatch platforms only; inline platforms skip)
|
- 1.3 Configure context `[required · once]` — Claude Code, Cursor, OpenCode, Codex, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Snow, Reasonix, Grok, Kimi Code (sub-agent-dispatch platforms only; inline platforms skip)
|
||||||
- 1.4 Activate task `[required · once]` (review gate, then `task.py start`; status → in_progress)
|
- 1.4 Activate task `[required · once]` (review gate, then `task.py start`; status → in_progress)
|
||||||
- 1.5 Completion criteria
|
- 1.5 Completion criteria
|
||||||
|
|
||||||
@@ -220,7 +220,7 @@ Inline mode: skip jsonl curation; Phase 2 reads artifacts/specs via `trellis-bef
|
|||||||
therefore must cover every required step from implementation through
|
therefore must cover every required step from implementation through
|
||||||
commit, including Phase 3.3 spec update and Phase 3.4 commit. -->
|
commit, including Phase 3.3 spec update and Phase 3.4 commit. -->
|
||||||
|
|
||||||
Sub-agent dispatch protocol applies to all platforms and all sub-agents, including class-2 Codex/Gemini/Qoder/Copilot/ZCode/Reasonix/Trae and `trellis-research`: every dispatch prompt starts with `Active task: <task path from task.py current>` before role-specific instructions.
|
Sub-agent dispatch protocol applies to all platforms and all sub-agents, including native Codex `SubagentStart` context injection with child-side pull fallback, class-2 Gemini/Qoder/Copilot/Reasonix/Trae/Grok/Kimi Code, hook-backed ZCode/Snow, and `trellis-research`: every dispatch prompt starts with `Active task: <task path from task.py current>` before role-specific instructions. On Grok Build, use `spawn_subagent` with `subagent_type` set to the Trellis agent name (e.g. `trellis-implement`). On Kimi Code, dispatch the built-in `coder` / `explore` sub-agent with the matching `.kimi-code/skills/trellis-<role>/SKILL.md` instructions.
|
||||||
|
|
||||||
[workflow-state:in_progress]
|
[workflow-state:in_progress]
|
||||||
Tools: `trellis-implement` / `trellis-research` are sub-agent types only (Task/Agent tool, NOT Skill; there is no skill by these names). `trellis-update-spec` is a skill. `trellis-check` exists as both; prefer the Agent form when verifying after code changes.
|
Tools: `trellis-implement` / `trellis-research` are sub-agent types only (Task/Agent tool, NOT Skill; there is no skill by these names). `trellis-update-spec` is a skill. `trellis-check` exists as both; prefer the Agent form when verifying after code changes.
|
||||||
@@ -272,13 +272,13 @@ Code committed. Run `/trellis:finish-work`; if dirty, return to Phase 3.4 first.
|
|||||||
|
|
||||||
When a user request matches one of these intents inside an active task, route first, then load the detailed phase step if needed.
|
When a user request matches one of these intents inside an active task, route first, then load the detailed phase step if needed.
|
||||||
|
|
||||||
[Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Reasonix, Trae]
|
[Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Snow, Reasonix, Trae, Grok, Kimi Code]
|
||||||
|
|
||||||
- Planning or unclear requirements -> `trellis-brainstorm`.
|
- Planning or unclear requirements -> `trellis-brainstorm`.
|
||||||
- `in_progress` implementation/check -> dispatch `trellis-implement` / `trellis-check`.
|
- `in_progress` implementation/check -> dispatch `trellis-implement` / `trellis-check`.
|
||||||
- Repeated debugging -> `trellis-break-loop`; spec updates -> `trellis-update-spec`.
|
- Repeated debugging -> `trellis-break-loop`; spec updates -> `trellis-update-spec`.
|
||||||
|
|
||||||
[/Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Reasonix, Trae]
|
[/Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Snow, Reasonix, Trae, Grok, Kimi Code]
|
||||||
|
|
||||||
[codex-inline, Kilo, Antigravity, Devin]
|
[codex-inline, Kilo, Antigravity, Devin]
|
||||||
|
|
||||||
@@ -353,7 +353,7 @@ Return to this step whenever requirements change and revise the relevant artifac
|
|||||||
|
|
||||||
Research can happen at any time during requirement exploration. It isn't limited to local code — you can use any available tool (MCP servers, skills, web search, etc.) to look up external information, including third-party library docs, industry practices, API references, etc.
|
Research can happen at any time during requirement exploration. It isn't limited to local code — you can use any available tool (MCP servers, skills, web search, etc.) to look up external information, including third-party library docs, industry practices, API references, etc.
|
||||||
|
|
||||||
[Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Reasonix, Trae]
|
[Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Snow, Reasonix, Trae, Grok, Kimi Code]
|
||||||
|
|
||||||
Spawn the research sub-agent:
|
Spawn the research sub-agent:
|
||||||
|
|
||||||
@@ -361,11 +361,11 @@ Spawn the research sub-agent:
|
|||||||
- **Task description**: Research <specific question>
|
- **Task description**: Research <specific question>
|
||||||
- **Key requirement**: Research output MUST be persisted to `{TASK_DIR}/research/`
|
- **Key requirement**: Research output MUST be persisted to `{TASK_DIR}/research/`
|
||||||
|
|
||||||
[/Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Reasonix, Trae]
|
[/Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Snow, Reasonix, Trae, Grok, Kimi Code]
|
||||||
|
|
||||||
[codex-inline, Kilo, Antigravity, Devin]
|
[codex-inline, Kilo, Antigravity, Devin]
|
||||||
|
|
||||||
Do the research in the main session directly and write findings into `{TASK_DIR}/research/`. (For `codex-inline` this avoids the `fork_turns="none"` isolation that prevents `trellis-research` sub-agents from resolving the active task path.)
|
Do the research in the main session directly and write findings into `{TASK_DIR}/research/`. `codex-inline` is the explicit mode that keeps work in the main session.
|
||||||
|
|
||||||
[/codex-inline, Kilo, Antigravity, Devin]
|
[/codex-inline, Kilo, Antigravity, Devin]
|
||||||
|
|
||||||
@@ -380,7 +380,7 @@ Brainstorm and research can interleave freely — pause to research a technical
|
|||||||
|
|
||||||
#### 1.3 Configure context `[required · once]`
|
#### 1.3 Configure context `[required · once]`
|
||||||
|
|
||||||
[Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Reasonix, Trae]
|
[Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Snow, Reasonix, Trae, Grok, Kimi Code]
|
||||||
|
|
||||||
Curate `implement.jsonl` and `check.jsonl` so the Phase 2 sub-agents get the right spec/research context. These files were seeded on `task create` with a single self-describing `_example` line; your job here is to fill in real entries.
|
Curate `implement.jsonl` and `check.jsonl` so the Phase 2 sub-agents get the right spec/research context. These files were seeded on `task create` with a single self-describing `_example` line; your job here is to fill in real entries.
|
||||||
|
|
||||||
@@ -425,7 +425,7 @@ Ready gate: both `implement.jsonl` and `check.jsonl` must contain at least one r
|
|||||||
|
|
||||||
Skip this step only when both files already have real curated entries.
|
Skip this step only when both files already have real curated entries.
|
||||||
|
|
||||||
[/Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Reasonix, Trae]
|
[/Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Snow, Reasonix, Trae, Grok, Kimi Code]
|
||||||
|
|
||||||
[codex-inline, Kilo, Antigravity, Devin]
|
[codex-inline, Kilo, Antigravity, Devin]
|
||||||
|
|
||||||
@@ -458,11 +458,11 @@ If `task.py start` errors with a session-identity message (no context key from h
|
|||||||
| `design.md` exists (complex tasks) | ✅ |
|
| `design.md` exists (complex tasks) | ✅ |
|
||||||
| `implement.md` exists (complex tasks) | ✅ |
|
| `implement.md` exists (complex tasks) | ✅ |
|
||||||
|
|
||||||
[Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Reasonix, Trae]
|
[Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Snow, Reasonix, Trae, Grok, Kimi Code]
|
||||||
|
|
||||||
| `implement.jsonl` and `check.jsonl` each contain at least one real curated entry (seed row does not count) | ✅ |
|
| `implement.jsonl` and `check.jsonl` each contain at least one real curated entry (seed row does not count) | ✅ |
|
||||||
|
|
||||||
[/Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Reasonix, Trae]
|
[/Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Snow, Reasonix, Trae, Grok, Kimi Code]
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -472,21 +472,22 @@ Goal: turn reviewed planning artifacts into code that passes quality checks.
|
|||||||
|
|
||||||
#### 2.1 Implement `[required · repeatable]`
|
#### 2.1 Implement `[required · repeatable]`
|
||||||
|
|
||||||
[Claude Code, Cursor, OpenCode, CodeBuddy, Droid, Pi, Oh My Pi]
|
[Claude Code, Cursor, OpenCode, codex-sub-agent, CodeBuddy, Droid, Pi, ZCode, Snow, Oh My Pi]
|
||||||
|
|
||||||
Spawn the implement sub-agent:
|
Spawn the implement sub-agent:
|
||||||
|
|
||||||
- **Agent type**: `trellis-implement`
|
- **Agent type**: `trellis-implement`
|
||||||
- **Task description**: Implement the reviewed task artifacts, consulting materials under `{TASK_DIR}/research/`; finish by running project lint and type-check
|
- **Task description**: Implement the reviewed task artifacts, consulting materials under `{TASK_DIR}/research/`; finish by running project lint and type-check
|
||||||
- **Dispatch prompt guard**: Tell the spawned agent it is already the `trellis-implement` sub-agent and must implement directly, not spawn another `trellis-implement` / `trellis-check`.
|
- **Dispatch prompt guard**: The prompt MUST start with `Active task: <task path>`, then tell the spawned agent it is already the `trellis-implement` sub-agent and must implement directly, not spawn another `trellis-implement` / `trellis-check`.
|
||||||
|
|
||||||
The platform hook/plugin auto-handles:
|
The platform hook/plugin auto-handles:
|
||||||
- Reads `implement.jsonl` and injects referenced spec/research files into the agent prompt
|
- Reads `implement.jsonl` and injects referenced spec/research files into the agent prompt
|
||||||
- Injects `prd.md`, `design.md` if present, and `implement.md` if present
|
- Injects `prd.md`, `design.md` if present, and `implement.md` if present
|
||||||
|
- For Codex, `SubagentStart` supplies native context injection; the agent profile keeps child-side loading as the fallback
|
||||||
|
|
||||||
[/Claude Code, Cursor, OpenCode, CodeBuddy, Droid, Pi, Oh My Pi]
|
[/Claude Code, Cursor, OpenCode, codex-sub-agent, CodeBuddy, Droid, Pi, ZCode, Snow, Oh My Pi]
|
||||||
|
|
||||||
[codex-sub-agent, Gemini, Qoder, Copilot, ZCode, Reasonix, Trae]
|
[Gemini, Qoder, Copilot, Reasonix, Trae, Grok, Kimi Code]
|
||||||
|
|
||||||
Spawn the implement sub-agent:
|
Spawn the implement sub-agent:
|
||||||
|
|
||||||
@@ -498,7 +499,7 @@ The pull-based sub-agent definition auto-handles the context load requirement:
|
|||||||
- Resolves the active task with `task.py current --source`, then reads `prd.md`, `design.md` if present, and `implement.md` if present
|
- Resolves the active task with `task.py current --source`, then reads `prd.md`, `design.md` if present, and `implement.md` if present
|
||||||
- Reads `implement.jsonl` and requires the agent to load each referenced spec/research file before coding
|
- Reads `implement.jsonl` and requires the agent to load each referenced spec/research file before coding
|
||||||
|
|
||||||
[/codex-sub-agent, Gemini, Qoder, Copilot, ZCode, Reasonix, Trae]
|
[/Gemini, Qoder, Copilot, Reasonix, Trae, Grok, Kimi Code]
|
||||||
|
|
||||||
[Kiro]
|
[Kiro]
|
||||||
|
|
||||||
@@ -526,13 +527,13 @@ The platform prelude auto-handles the context load requirement:
|
|||||||
|
|
||||||
#### 2.2 Quality check `[required · repeatable]`
|
#### 2.2 Quality check `[required · repeatable]`
|
||||||
|
|
||||||
[Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Reasonix, Trae]
|
[Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Snow, Reasonix, Trae, Grok, Kimi Code]
|
||||||
|
|
||||||
Spawn the check sub-agent:
|
Spawn the check sub-agent:
|
||||||
|
|
||||||
- **Agent type**: `trellis-check`
|
- **Agent type**: `trellis-check`
|
||||||
- **Task description**: Review all code changes against specs and task artifacts; fix any findings directly; ensure lint and type-check pass
|
- **Task description**: Review all code changes against specs and task artifacts; fix any findings directly; ensure lint and type-check pass
|
||||||
- **Dispatch prompt guard**: Tell the spawned agent it is already the `trellis-check` sub-agent and must review/fix directly, not spawn another `trellis-check` / `trellis-implement`.
|
- **Dispatch prompt guard**: The prompt MUST start with `Active task: <task path>`, then tell the spawned agent it is already the `trellis-check` sub-agent and must review/fix directly, not spawn another `trellis-check` / `trellis-implement`.
|
||||||
|
|
||||||
The check agent's job:
|
The check agent's job:
|
||||||
- Review code changes against specs
|
- Review code changes against specs
|
||||||
@@ -540,7 +541,7 @@ The check agent's job:
|
|||||||
- Auto-fix issues it finds
|
- Auto-fix issues it finds
|
||||||
- Run lint and typecheck to verify
|
- Run lint and typecheck to verify
|
||||||
|
|
||||||
[/Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Reasonix, Trae]
|
[/Claude Code, Cursor, OpenCode, codex-sub-agent, Kiro, Gemini, Qoder, CodeBuddy, Copilot, Droid, Pi, Oh My Pi, ZCode, Snow, Reasonix, Trae, Grok, Kimi Code]
|
||||||
|
|
||||||
[codex-inline, Kilo, Antigravity, Devin]
|
[codex-inline, Kilo, Antigravity, Devin]
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,22 @@
|
|||||||
|
|
||||||
格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/)(版本段不记日期),版本号遵循语义化版本。
|
格式参考 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/)(版本段不记日期),版本号遵循语义化版本。
|
||||||
|
|
||||||
|
## [0.8.3]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- 新增通行密钥(Passkey / WebAuthn)注册、管理与免用户名登录,要求验证器完成用户验证;新增 Web3 钱包绑定与 EIP-4361 签名登录,支持浏览器注入的 EOA 钱包
|
||||||
|
- 新增活跃会话管理:按登录方式、客户端 IP、User-Agent 与最近活跃时间查看当前账号会话,可定点撤销其他会话;敏感变更换发令牌时接续原会话,升级前签发的存量令牌保持兼容
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- 租户 API Key 激活接口支持切换到租户内其他 IAM 用户,验证新密钥可用后同步更新面板签名用户与凭据
|
||||||
|
- 禁用密码登录时将通行密钥计入可用免密方式,并阻止删除最后一种可用登录方式,避免账号自锁
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- 同一实例的终止与电源操作增加飞行期互斥,重复请求稳定返回 409,避免并发执行相互冲突的生命周期操作
|
||||||
|
|
||||||
## [0.8.2]
|
## [0.8.2]
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
+1
-1
@@ -1 +1 @@
|
|||||||
v0.8.2
|
v0.8.3
|
||||||
|
|||||||
+1
-1
@@ -31,7 +31,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// @title OCI Portal API
|
// @title OCI Portal API
|
||||||
// @version 0.8.2
|
// @version 0.8.3
|
||||||
// @description 自托管 OCI 多租户管理面板 API。业务接口用 JWT(Bearer);AI 网关端点(/ai/v1/*)用独立网关密钥(Authorization: Bearer 或 x-api-key)。
|
// @description 自托管 OCI 多租户管理面板 API。业务接口用 JWT(Bearer);AI 网关端点(/ai/v1/*)用独立网关密钥(Authorization: Bearer 或 x-api-key)。
|
||||||
// @BasePath /
|
// @BasePath /
|
||||||
// @securityDefinitions.apikey BearerAuth
|
// @securityDefinitions.apikey BearerAuth
|
||||||
|
|||||||
+1
-1
@@ -12723,7 +12723,7 @@ const docTemplate = `{
|
|||||||
|
|
||||||
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
// SwaggerInfo holds exported Swagger Info so clients can modify it
|
||||||
var SwaggerInfo = &swag.Spec{
|
var SwaggerInfo = &swag.Spec{
|
||||||
Version: "0.8.2",
|
Version: "0.8.3",
|
||||||
Host: "",
|
Host: "",
|
||||||
BasePath: "/",
|
BasePath: "/",
|
||||||
Schemes: []string{},
|
Schemes: []string{},
|
||||||
|
|||||||
+1
-1
@@ -4,7 +4,7 @@
|
|||||||
"description": "自托管 OCI 多租户管理面板 API。业务接口用 JWT(Bearer);AI 网关端点(/ai/v1/*)用独立网关密钥(Authorization: Bearer 或 x-api-key)。",
|
"description": "自托管 OCI 多租户管理面板 API。业务接口用 JWT(Bearer);AI 网关端点(/ai/v1/*)用独立网关密钥(Authorization: Bearer 或 x-api-key)。",
|
||||||
"title": "OCI Portal API",
|
"title": "OCI Portal API",
|
||||||
"contact": {},
|
"contact": {},
|
||||||
"version": "0.8.2"
|
"version": "0.8.3"
|
||||||
},
|
},
|
||||||
"basePath": "/",
|
"basePath": "/",
|
||||||
"paths": {
|
"paths": {
|
||||||
|
|||||||
+1
-1
@@ -3146,7 +3146,7 @@ info:
|
|||||||
description: '自托管 OCI 多租户管理面板 API。业务接口用 JWT(Bearer);AI 网关端点(/ai/v1/*)用独立网关密钥(Authorization:
|
description: '自托管 OCI 多租户管理面板 API。业务接口用 JWT(Bearer);AI 网关端点(/ai/v1/*)用独立网关密钥(Authorization:
|
||||||
Bearer 或 x-api-key)。'
|
Bearer 或 x-api-key)。'
|
||||||
title: OCI Portal API
|
title: OCI Portal API
|
||||||
version: 0.8.2
|
version: 0.8.3
|
||||||
paths:
|
paths:
|
||||||
/ai/v1/audio/speech:
|
/ai/v1/audio/speech:
|
||||||
post:
|
post:
|
||||||
|
|||||||
Reference in New Issue
Block a user