Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
284 commits
Select commit Hold shift + click to select a range
5366e93
refactor(yjs): remove saved entity field overlays
BruzWJ Jun 21, 2026
8fea596
fix(copilot): persist server tool review tokens
BruzWJ Jun 21, 2026
fb8ff93
fix(mcp): reject reused device login approvals
BruzWJ Jun 21, 2026
a3c4ea1
fix(workflows): avoid loading deployed workflow variables
BruzWJ Jun 21, 2026
4ca9b51
fix(mcp): authenticate device login API keys
BruzWJ Jun 21, 2026
0835d96
fix(copilot): apply reviewed tool changes atomically
BruzWJ Jun 21, 2026
2b94ebe
fix(copilot): prevent stale server tool review acceptance
BruzWJ Jun 21, 2026
164ee90
fix(copilot): handle malformed MCP batch entries
BruzWJ Jun 21, 2026
4bb55c8
feat(copilot): stage mutation tools for review
BruzWJ Jun 21, 2026
f34626b
fix(copilot): prevent sensitive tool payload exposure
BruzWJ Jun 21, 2026
82adab9
docs: update project agent testing guidance
BruzWJ Jun 21, 2026
3dcf4be
fix(copilot): reject empty JSON-RPC batches
BruzWJ Jun 21, 2026
6cbb24d
fix(copilot): redact managed review secrets
BruzWJ Jun 21, 2026
12d81b4
feat(mcp): use personal API keys for device login
BruzWJ Jun 21, 2026
adb0dd4
fix(mcp): issue device login keys during approval polling
BruzWJ Jun 21, 2026
bdf6e56
fix(workflows): preserve deployment metadata from saved state
BruzWJ Jun 21, 2026
5a4b50b
fix(mcp): use shared personal api key auth
BruzWJ Jun 21, 2026
b87fc13
fix(workflows): preserve variables during direct yjs persistence
BruzWJ Jun 21, 2026
4d0241d
fix(workflows): persist workflow names through Yjs state
BruzWJ Jun 21, 2026
fc436b4
fix(copilot): read saved entities from bootstrapped Yjs state
BruzWJ Jun 21, 2026
d7f4850
feat(editors): back entity editors with Yjs sessions
BruzWJ Jun 21, 2026
c39cd33
feat(workflows): export referenced skills from Yjs state
BruzWJ Jun 21, 2026
e78ab77
fix(mcp): consume device login approvals when issuing keys
BruzWJ Jun 21, 2026
d984f06
fix(yjs): fall back to direct state persistence on apply errors
BruzWJ Jun 21, 2026
ee6fd42
fix(custom-tools): reject duplicate titles on update
BruzWJ Jun 21, 2026
20ac127
fix(copilot): omit generated workflow ids from review staging
BruzWJ Jun 21, 2026
8dfcd65
fix(copilot): require workflow variable ids in documents
BruzWJ Jun 21, 2026
560b549
style(copilot): wrap copilot registry assertions
BruzWJ Jun 21, 2026
cce91db
feat(copilot): refresh state after server tool mutations
BruzWJ Jun 21, 2026
420d525
fix(copilot): serialize server tool review acceptance
BruzWJ Jun 21, 2026
db6b07c
fix(workflows): persist normalized workflow state
BruzWJ Jun 21, 2026
62580b1
fix(auth): preserve locale on invalid MCP authorization
BruzWJ Jun 21, 2026
5c7c3c6
fix(copilot): reject stale accepted server tool reviews
BruzWJ Jun 21, 2026
b3f224c
fix(yjs): keep saved entity sessions noncanonical
BruzWJ Jun 21, 2026
2813eda
fix(workflows): preserve deployment metadata from live state
BruzWJ Jun 21, 2026
ffebf07
fix(yjs): separate saved entity draft persistence
BruzWJ Jun 21, 2026
e60fe7c
fix(workflows): handle missing normalized saved state
BruzWJ Jun 21, 2026
abf674f
fix(copilot): scope environment variable writes to workspace
BruzWJ Jun 21, 2026
15af5d3
style(mcp): reorder authorize page imports
BruzWJ Jun 21, 2026
4ba4ee0
feat(mcp): issue device login keys from approval state
BruzWJ Jun 21, 2026
abe9818
fix(api-key): require complete key format for lookup
BruzWJ Jun 21, 2026
e9c16c0
fix(copilot): persist accepted reviewed entity updates
BruzWJ Jun 21, 2026
935c221
fix(api-keys): bind generated key material to stored id
BruzWJ Jun 22, 2026
e40590f
fix(copilot): pass workspace context to environment writes
BruzWJ Jun 22, 2026
6bc4146
style(copilot): wrap credential prompt metadata
BruzWJ Jun 22, 2026
9d332c6
docs(mcp): clarify device grant retry window
BruzWJ Jun 22, 2026
f73a113
fix(mcp): make device login delivery idempotent
BruzWJ Jun 22, 2026
26809fb
fix(yjs): persist state before applying document updates
BruzWJ Jun 22, 2026
e8698a9
fix(yjs): refresh stale saved target snapshots
BruzWJ Jun 22, 2026
7ff5782
fix(yjs): make saved entity persistence best effort
BruzWJ Jun 22, 2026
c2d5b9e
feat(copilot): scope environment variable mutations
BruzWJ Jun 22, 2026
127087c
fix(copilot): align contracts after staging rebase
BruzWJ Jun 23, 2026
705863c
fix(copilot): align indicator runtime contracts
BruzWJ Jun 23, 2026
f73e357
feat(yjs): persist saved entity session edits
BruzWJ Jun 23, 2026
6d03e1a
fix(copilot): preserve MCP server secrets in documents
BruzWJ Jun 23, 2026
10c32a2
fix(yjs): apply snapshots before database persistence
BruzWJ Jun 23, 2026
8fedcb9
test(copilot): update test files
BruzWJ Jun 23, 2026
ce2b89a
fix(copilot): normalize entity document fields
BruzWJ Jun 23, 2026
479e585
test(copilot): cover entity document normalization
BruzWJ Jun 23, 2026
8f957ef
fix(mcp): require urls for URL transports
BruzWJ Jun 23, 2026
d812e46
feat(copilot): support personal scoped credential reads
BruzWJ Jun 23, 2026
321e6c6
refactor(yjs): simplify saved entity state sync
BruzWJ Jun 23, 2026
24a6c27
fix(yjs): persist applied snapshots from live documents
BruzWJ Jun 24, 2026
aa089d3
fix(api-key): reject malformed keys before lookup
BruzWJ Jun 24, 2026
866dc2a
feat(yjs): persist workflow session state through the socket bridge
BruzWJ Jun 24, 2026
1fcbbff
feat(api-key): remove embedded ids from generated api keys
BruzWJ Jun 24, 2026
138ca5b
fix(copilot): keep review acceptance bound to the staged execution co…
BruzWJ Jun 24, 2026
1f4b72c
feat(auth): simplify MCP device login approval flow
BruzWJ Jun 24, 2026
dc709ab
feat(copilot): improve workflow editing and tool routing
BruzWJ Jun 24, 2026
b0bb61a
feat(workflows): persist workflow state to normalized tables
BruzWJ Jun 24, 2026
f273641
fix(yjs): stop deleting live sessions during cleanup
BruzWJ Jun 24, 2026
52b081a
test(trading): cache the order route handler in the test
BruzWJ Jun 24, 2026
1ee6511
feat(workflows): preserve workflow variables during import and revert
BruzWJ Jun 24, 2026
c98e8a6
fix(yjs): restore saved entity state from db on materialization failure
BruzWJ Jun 24, 2026
2b2a14c
feat(workflow): rename workflow metadata without republishing state
BruzWJ Jun 24, 2026
599ffd7
feat(indicators): carry color through copilot entity documents
BruzWJ Jun 24, 2026
e5bc23e
docs(changelog): add June 24 Copilot MCP branch summary
BruzWJ Jun 24, 2026
2031c81
fix(copilot): deny inaccessible workspaces in server tools
BruzWJ Jun 24, 2026
5495906
fix(mcp): limit delivery retries when polling device login
BruzWJ Jun 24, 2026
102ed5e
fix(yjs): restore workflow state after persistence failure
BruzWJ Jun 24, 2026
4bbe32f
fix(workflows): load normalized workflow state consistently
BruzWJ Jun 24, 2026
02f9b0d
fix(yjs): preserve refresh error cause
BruzWJ Jun 24, 2026
ef9edee
feat(mcp-auth): rate-limit device login starts per requester
BruzWJ Jun 24, 2026
5384643
feat(copilot-mcp): allowlist external server tools
BruzWJ Jun 24, 2026
477e278
style(yjs): reformat snapshot bridge import
BruzWJ Jun 24, 2026
c17de55
feat(api): add shared MCP rate limiting
BruzWJ Jun 24, 2026
c02534f
fix(mcp): use configured base URLs in installer flows
BruzWJ Jun 24, 2026
6d91300
refactor(copilot): make MCP tool exposure explicit
BruzWJ Jun 24, 2026
e549b39
fix(ui): clear help modal scroll timer
BruzWJ Jun 24, 2026
546049e
feat(api-key): hash stored keys and simplify auth
BruzWJ Jun 24, 2026
893d6a2
build(config): remove API_ENCRYPTION_KEY from deployment samples
BruzWJ Jun 24, 2026
980388e
docs(api-key): remove API_ENCRYPTION_KEY references
BruzWJ Jun 24, 2026
c5949b4
style(ui): normalize tool call and copilot route formatting
BruzWJ Jun 24, 2026
ecf2fc8
feat(auth): bind MCP approval to a user challenge
BruzWJ Jun 24, 2026
c7b7033
feat(api-key): stop exposing raw API keys in lists
BruzWJ Jun 24, 2026
17cff32
refactor(operations): prefetch existing workspace entities during upsert
BruzWJ Jun 24, 2026
26c0803
fix(auth): generate MCP api keys at approval time
BruzWJ Jun 24, 2026
421f7aa
fix(mcp): scope public MCP login starts to the deployment
BruzWJ Jun 24, 2026
74bd54e
feat(auth): sign MCP device login codes
BruzWJ Jun 25, 2026
f668a29
refactor(workspace): split entity writes and clean up Yjs sessions
BruzWJ Jun 25, 2026
f422fdd
feat(workflows): load workflow state through the Yjs snapshot bridge
BruzWJ Jun 25, 2026
8b9764c
fix(mcp): harden device login approval challenge handling
BruzWJ Jun 25, 2026
def05e8
feat(api): scope endpoint rate limits by endpoint type
BruzWJ Jun 25, 2026
5821043
fix(mcp): ignore malformed client configs when reading tokens
BruzWJ Jun 25, 2026
d785788
fix(yjs): make socket cleanup non-blocking after data mutation
BruzWJ Jun 25, 2026
a904006
fix(mcp): preserve cancelled device login state
BruzWJ Jun 25, 2026
c640cc9
fix(copilot): run accepted review before consuming token row
BruzWJ Jun 25, 2026
b890d71
fix(copilot): claim server tool review tokens before execution
BruzWJ Jun 25, 2026
ae3b238
fix(mcp): derive approval tokens from device login code
BruzWJ Jun 25, 2026
c0c9a46
fix(yjs): persist deployment status from workflow state
BruzWJ Jun 25, 2026
12aee05
fix(mcp): rate-limit device login starts and scope approvals
BruzWJ Jun 25, 2026
69d9cf3
feat(api-key): encrypt stored API keys
BruzWJ Jun 25, 2026
6d29b46
feat(mcp): persist device login state
BruzWJ Jun 25, 2026
8afd1d1
fix(yjs): remove DB refresh fallback after persistence failures
BruzWJ Jun 25, 2026
5156c08
feat(indicator): surface save failures in code panel
BruzWJ Jun 25, 2026
bcf07b6
feat(workflow): surface auto-layout failures in control bar
BruzWJ Jun 25, 2026
c5f9514
feat(api-key): add optional API key encryption
BruzWJ Jun 25, 2026
24e8d50
feat(auth): rate-limit MCP login starts
BruzWJ Jun 25, 2026
e20d45f
feat(yjs): bootstrap live sessions from saved snapshots
BruzWJ Jun 25, 2026
328bb50
feat(mcp): defer device login persistence to approval
BruzWJ Jun 25, 2026
c376d1e
refactor(copilot): require resolved review target runtime
BruzWJ Jun 25, 2026
0d70317
feat(copilot): expose mutation tools to trusted agents
BruzWJ Jun 25, 2026
a83bc85
refactor(workflows): move variable remapping into import export
BruzWJ Jun 25, 2026
0c4b925
test(yjs): cover bridge failure propagation
BruzWJ Jun 25, 2026
5d50599
fix(api-key): reject malformed keys before lookup
BruzWJ Jun 25, 2026
dbdfcf9
refactor(yjs): centralize state persistence in socket server
BruzWJ Jun 25, 2026
9c6db3c
feat(mcp): rate limit public MCP auth endpoints
BruzWJ Jun 25, 2026
a393925
fix(yjs): discard idle documents after failed persistence
BruzWJ Jun 25, 2026
3c90792
style(queue): format execution limiter test
BruzWJ Jun 25, 2026
63dafba
feat(workflows): sync workflow metadata through yjs state
BruzWJ Jun 25, 2026
c846376
fix(api): ignore user agent in rate limit keys
BruzWJ Jun 25, 2026
9a76243
refactor(workflows): separate editable state from deployment metadata
BruzWJ Jun 25, 2026
bcb765a
fix(mcp): always authenticate installer sessions
BruzWJ Jun 25, 2026
89e5643
feat(mcp): acknowledge device login token activation
BruzWJ Jun 25, 2026
72722ac
refactor(workflows): read editable state from Yjs sessions
BruzWJ Jun 25, 2026
47875ed
fix(workflows): validate and persist workflow names
BruzWJ Jun 25, 2026
d5429a3
style(yjs): format workflow session tests
BruzWJ Jun 25, 2026
7053605
fix(mcp): acknowledge login before config writes
BruzWJ Jun 25, 2026
4e1684c
feat(yjs): support partial workflow patches
BruzWJ Jun 25, 2026
28b95c1
fix(saved-entities): map duplicate names to validation errors
BruzWJ Jun 25, 2026
546ba47
fix(workflows): load live execution state through Yjs sessions
BruzWJ Jun 25, 2026
1736fee
fix(yjs): rewrite variable references on replacement
BruzWJ Jun 25, 2026
5a7b3c9
fix(workflows): export skills from workspace store
BruzWJ Jun 25, 2026
11e0a71
fix(mcp): reuse approved device login api key
BruzWJ Jun 25, 2026
0931bbd
fix(yjs): skip idle persistence for clean documents
BruzWJ Jun 25, 2026
1bff0e7
fix(copilot): require explicit workflow variable removal intent
BruzWJ Jun 25, 2026
1cf99bd
fix(yjs): retry transient snapshot bridge fetches
BruzWJ Jun 25, 2026
17ffeaf
fix(yjs): clear reseed metadata after variable replacement
BruzWJ Jun 25, 2026
8628f04
feat(workflows): persist embedded custom tools
BruzWJ Jun 25, 2026
c0b5b32
fix(workflows): surface realtime orchestration failures
BruzWJ Jun 25, 2026
c8f6ac4
fix(rate-limit): fail closed for public MCP auth limits
BruzWJ Jun 25, 2026
c4760d8
fix(copilot): rate limit public MCP requests before auth
BruzWJ Jun 25, 2026
7d94f60
fix(workflows): standardize realtime-required API responses
BruzWJ Jun 25, 2026
e51cf12
fix(copilot): normalize MCP server header records
BruzWJ Jun 25, 2026
6208435
fix(workflows): sanitize agent tools during normalized saves
BruzWJ Jun 26, 2026
1f3ece9
fix(workflows): require realtime state for editable workflows
BruzWJ Jun 26, 2026
d77f617
fix(knowledge): surface saved entity persistence errors
BruzWJ Jun 26, 2026
84882b2
fix(workflows): surface realtime orchestration failures
BruzWJ Jun 26, 2026
5506de4
feat(indicators): infer input metadata from pine code
BruzWJ Jun 26, 2026
2dda658
fix(auth): preserve locale in MCP authorize callbacks
BruzWJ Jun 26, 2026
a849813
fix(yjs): surface socket bridge snapshot errors
BruzWJ Jun 26, 2026
ed756aa
fix(yjs): require realtime persistence for saved entities
BruzWJ Jun 26, 2026
9a10cd9
feat(monitor): refresh pages after server tool updates
BruzWJ Jun 26, 2026
98783e1
style(monitor): apply formatting cleanup
BruzWJ Jun 26, 2026
1f5e621
feat(mcp): use dedicated api key type
BruzWJ Jun 26, 2026
ddaa809
feat(mcp): hydrate server configs from saved entity state
BruzWJ Jun 26, 2026
71d5490
fix(mcp): validate server fields consistently
BruzWJ Jun 26, 2026
b2a0d18
fix(yjs): stage apply mutations before persistence
BruzWJ Jun 26, 2026
151a0a0
fix(yjs): scope saved entity materialization by workspace
BruzWJ Jun 26, 2026
61f21e5
refactor(api-key): use personal keys for mcp access
BruzWJ Jun 26, 2026
7237f92
fix(mcp): bootstrap workspaces for copilot initialize
BruzWJ Jun 26, 2026
6c1434b
fix(mcp): sanitize copilot rpc errors
BruzWJ Jun 26, 2026
93ee1c8
feat(yjs): read saved entity state through canonical sessions
BruzWJ Jun 26, 2026
359c222
fix(yjs): skip invalid saved entity list rows
BruzWJ Jun 26, 2026
e2cdf7e
feat(yjs): add entity-list bootstrap sessions
BruzWJ Jun 26, 2026
2ae46e4
test(socket-server): keep connected saved entity drafts on save failure
BruzWJ Jun 26, 2026
ac118d9
docs(socket-server): clarify explicit-save draft persistence
BruzWJ Jun 26, 2026
ffab7ce
refactor(tradinggoose): simplify resource metadata and sorting
BruzWJ Jun 27, 2026
c4e9d06
fix(mcp): show visible MCP servers in selectors
BruzWJ Jun 27, 2026
2372442
fix(mcp): preserve server state across refreshes
BruzWJ Jun 27, 2026
6770e0c
feat(mcp): propagate enabled state through MCP server lists
BruzWJ Jun 27, 2026
3e35b92
fix(workflows): use bootstrap state for deploy and status checks
BruzWJ Jun 27, 2026
275e022
fix(mcp): synchronize server refresh and membership state
BruzWJ Jun 27, 2026
14ac1a4
fix(workflows): clarify editable realtime requirement
BruzWJ Jun 27, 2026
b6d8f2c
test: align mocks with current imports
BruzWJ Jun 27, 2026
959425e
fix(custom-tools): allow workflow-scoped lookup
BruzWJ Jun 27, 2026
fd2a473
feat(mcp): refresh discovered tools after server mutations
BruzWJ Jun 27, 2026
5cb00fd
test(socket-server): cover failed skill update on connected drafts
BruzWJ Jun 27, 2026
f47e631
fix(mcp): return 404 when servers are missing
BruzWJ Jun 27, 2026
48499e9
fix(workflows): handle realtime-required workflow state errors
BruzWJ Jun 27, 2026
eff7328
fix(yjs): stabilize saved-entity list sync
BruzWJ Jun 27, 2026
4e140f5
feat(api-key): require encrypted API-key storage
BruzWJ Jun 27, 2026
6684fb6
feat(yjs): sync entity lists from saved entity writes
BruzWJ Jun 27, 2026
c9324f1
build(config): relax API encryption key requirement
BruzWJ Jun 27, 2026
a1c69ad
docs(config): update API encryption key guidance
BruzWJ Jun 27, 2026
020b92b
feat(mcp): persist server status and refresh metadata
BruzWJ Jun 27, 2026
373c47e
fix(yjs): clean up sessions before deleting entities
BruzWJ Jun 27, 2026
3410557
test(mcp): cover config writer targets
BruzWJ Jun 27, 2026
21030e4
feat(mcp): sync MCP server API with database records
BruzWJ Jun 27, 2026
8836233
fix(auth): gate API key and MCP routes on storage availability
BruzWJ Jun 27, 2026
5d9d7ca
fix(copilot): base review hashes on current entity state
BruzWJ Jun 27, 2026
c6361fb
fix(yjs): keep saved entity projections in sync
BruzWJ Jun 27, 2026
87c7487
perf(yjs): parallelize bootstrapped field reads
BruzWJ Jun 27, 2026
4c6449f
fix(yjs): surface realtime-required snapshot errors
BruzWJ Jun 27, 2026
7c0839f
feat(copilot): auto-create MCP workspaces
BruzWJ Jun 27, 2026
d0d0a44
fix(knowledge): make knowledge base notifications transactional
BruzWJ Jun 27, 2026
b43c3bb
feat(yjs): persist workflow docs on live updates
BruzWJ Jun 27, 2026
878b913
feat(realtime): surface realtime sync errors from saved entity writes
BruzWJ Jun 28, 2026
5c35844
refactor(mcp): centralize workspace server creation
BruzWJ Jun 28, 2026
124942b
fix(mcp): refresh tool cache when server metadata changes
BruzWJ Jun 28, 2026
9199380
fix(workflow): debounce live Yjs persistence
BruzWJ Jun 28, 2026
2de8e0c
fix(copilot): enforce workspace-scoped review targets
BruzWJ Jun 28, 2026
7c9e956
fix(yjs): rollback created members on publish failure
BruzWJ Jun 28, 2026
80e5ff0
refactor(mcp): rename server update action
BruzWJ Jun 28, 2026
4366ca7
fix(yjs): keep live entity docs in sync after persistence
BruzWJ Jun 28, 2026
7c84d13
fix(copilot): harden MCP initialize handling
BruzWJ Jun 28, 2026
3635568
refactor(copilot): internalize entity helper utilities
BruzWJ Jun 28, 2026
50a62de
docs(changelog): remove stale June 24 entry
BruzWJ Jun 28, 2026
d71fa13
refactor(copilot): remove legacy typed server tool error path
BruzWJ Jun 28, 2026
30714fd
fix(mcp): remove stale MCP tool cache
BruzWJ Jun 28, 2026
c17f53b
feat(mcp): harden MCP server workspace handling
BruzWJ Jun 28, 2026
e74e3a9
fix(mcp): derive base URLs from request origin and acknowledge delive…
BruzWJ Jun 28, 2026
7075bc8
fix(copilot): accept MCP 2025-06-18 and workflow variable errors
BruzWJ Jun 28, 2026
a1c329d
fix(mcp): support protocol negotiation and install ack timing
BruzWJ Jun 28, 2026
c81fd23
refactor(realtime): rename editable bootstrap helpers
BruzWJ Jun 28, 2026
277bedb
fix(workspaces): prevent deleting the last workspace
BruzWJ Jun 28, 2026
301d1d5
fix(workspaces): move bootstrap to signup and refresh MCP tools
BruzWJ Jun 28, 2026
a953ba7
fix(workspaces): create default workspace when user has none
BruzWJ Jun 28, 2026
820c0c1
fix(stores): clear react query cache during user data reset
BruzWJ Jun 28, 2026
4070299
fix(workspaces): stop auto-creating workspaces on read
BruzWJ Jun 28, 2026
f490698
fix(workflows): remap duplicate block references in sub-blocks
BruzWJ Jun 28, 2026
ec06136
fix(api-key): validate encryption key availability
BruzWJ Jun 28, 2026
9ab9b5b
fix(query-provider): use browser-scoped query client
BruzWJ Jun 28, 2026
ad90f23
feat(workspace): create default workspace for root entry
BruzWJ Jun 28, 2026
4cd0370
feat(workspaces): bootstrap default workspace for MCP users
BruzWJ Jun 28, 2026
3423264
feat(mcp): use configured app URL for auth and install flows
BruzWJ Jun 28, 2026
d311c85
feat(mcp): support MCP 2025-06-18 negotiation
BruzWJ Jun 28, 2026
d56019b
fix(api-key): handle unconfigured storage consistently
BruzWJ Jun 28, 2026
ebc6208
fix(mcp): normalize protocol negotiation and JSON-RPC handling
BruzWJ Jun 28, 2026
7f38fb7
fix(workflows): return conflict when editable workflow state is missing
BruzWJ Jun 29, 2026
5556d4b
feat(mcp): allow disabled server drafts without a url
BruzWJ Jun 29, 2026
933199d
fix(mcp): align server mutations with realtime review sessions
BruzWJ Jun 29, 2026
7c61fdf
docs(changelog): add June 28 2026 staging changelog
BruzWJ Jun 29, 2026
d60260e
fix(mcp): tolerate cleanup failures after MCP server delete
BruzWJ Jun 29, 2026
908cde9
fix(api-key): reject legacy stored api-key rows
BruzWJ Jun 29, 2026
9aef90e
docs(readme): add Copilot-MCP setup instructions
BruzWJ Jun 29, 2026
036be1d
feat(workflows): persist workflow state through Yjs materialization
BruzWJ Jun 29, 2026
711f208
fix(workflows): persist auto-layout durably
BruzWJ Jun 29, 2026
f33664e
test: stabilize workflow and heatmap assertions
BruzWJ Jun 29, 2026
dccab73
feat(copilot): surface entity enabled state and tighten rename valida…
BruzWJ Jun 29, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1 +1 @@
bunx lint-staged
bunx lint-staged
3 changes: 1 addition & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@
- Do not add legacy support; updates should be clean and avoid extra project complexity.
- We do not need any form of legacy support as the project is under fresh dev, do not add any form of legacy backfill path
- This project does not support any legacy methods.
- Ignore all license related issues.
- Project uses `Bun` pacakge manager with turborepo.
- Project uses `Bun` pacakge manager with turborepo, find project defined scripts in `/pacakge.json` for testing.
- Prefer removing lines of code over adding more lines of code to reduce project complexity.

## Planning
Expand Down
38 changes: 31 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,33 @@ It is built for analytics, research, charting, monitoring, and workflow automati
<img alt="Project Overview" src="apps/tradinggoose/public/static/preview-light.png" width="2559">
</picture>

---

### Copilot-MCP

You can install TradingGoose MCP to use any local agentic tool like Codex, Claude Code, Cursor, ZCode as Copilot to perform TradingGoose-Studio operations

#### Mac/Linux:
connect to the hosted instance:
```
curl -fsSL https://TradingGoose.ai/mcp/setup | sh
```

connect to self-hosted instance:
```
curl -fsSL http://localhost:3000/mcp/setup | sh
```

#### Windows
connect to the hosted instance:
```
irm https://TradingGoose.ai/mcp/setup | iex
```

connect to self-hosted instance:
```
irm http://localhost:3000/mcp/setup | iex
```

## Quick Start

Expand Down Expand Up @@ -86,12 +112,10 @@ cd ../../packages/db && cp .env.example .env

#### 4. Run database migrations
```
cd packages/db
bunx drizzle-kit migrate --config=./drizzle.config.ts
bun run db:migrate
```
#### 5. Start development servers
#### 5. Start full development servers
```
cd ../..
bun run dev:full
```

Expand All @@ -101,9 +125,9 @@ If you use Docker Compose, copy `apps/tradinggoose/.env.example.docker` to
`apps/tradinggoose/.env` and set the required secrets before running the
compose manifests. The `.env` must include `POSTGRES_*`,
`NEXT_PUBLIC_APP_URL`, `NEXT_PUBLIC_SOCKET_URL`, `BETTER_AUTH_SECRET`,
`ENCRYPTION_KEY`, `API_ENCRYPTION_KEY`, and `INTERNAL_API_SECRET`. The
`ENCRYPTION_KEY` value is shared by both the app and realtime containers, and
`API_ENCRYPTION_KEY` enables encrypted API-key storage in the app container.
`ENCRYPTION_KEY`, and `INTERNAL_API_SECRET`. Set `API_ENCRYPTION_KEY` when
API-key access or MCP token issuance is used; it encrypts API keys at rest in
the app container.
`NEXT_PUBLIC_SOCKET_URL` should point at `http://localhost:3002` for local
Compose runs; production deployments must override it with a browser-reachable
public URL. The prod and Ollama compose files also require `IMAGE_TAG` and
Expand Down
4 changes: 2 additions & 2 deletions apps/tradinggoose/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ BETTER_AUTH_SECRET="replace-with-64-hex-characters"
# Generate a secure 64-character hex secret.
ENCRYPTION_KEY="replace-with-64-hex-characters"

# Recommended: dedicated encryption key for stored API credentials.
# Optional unless API-key access or MCP token issuance is used.
# Generate a secure 64-character hex secret.
API_ENCRYPTION_KEY="replace-with-64-hex-characters"
API_ENCRYPTION_KEY=""

# Required: internal server-to-server auth secret used by app routes, sockets,
# cron endpoints, and other internal calls.
Expand Down
3 changes: 3 additions & 0 deletions apps/tradinggoose/.env.example.docker
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ OLLAMA_IMAGE_TAG=latest
# Security (Required)
# Use `openssl rand -hex 32` to generate, used to encrypt environment variables
ENCRYPTION_KEY=generate-the-key
# Optional unless API-key access or MCP token issuance is used.
# Use `openssl rand -hex 32` to generate, used to encrypt API keys
API_ENCRYPTION_KEY=
# Use `openssl rand -hex 32` to generate, used to encrypt internal api routes
INTERNAL_API_SECRET=generate-the-secret

Expand Down
101 changes: 101 additions & 0 deletions apps/tradinggoose/app/[locale]/(auth)/mcp/authorize/page.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import type React from 'react'
import { renderToStaticMarkup } from 'react-dom/server'
import { beforeEach, describe, expect, it, vi } from 'vitest'

const {
mockGetSession,
mockGetSessionCookie,
mockHeaders,
mockCreateMcpDeviceLoginApprovalChallenge,
mockRedirect,
} = vi.hoisted(() => ({
mockCreateMcpDeviceLoginApprovalChallenge: vi.fn(),
mockGetSession: vi.fn(),
mockGetSessionCookie: vi.fn(),
mockHeaders: vi.fn(),
mockRedirect: vi.fn(),
}))

vi.mock('next/headers', () => ({
headers: () => mockHeaders(),
}))

vi.mock('better-auth/cookies', () => ({
getSessionCookie: (...args: unknown[]) => mockGetSessionCookie(...args),
}))

vi.mock('@/lib/auth', () => ({
getSession: (...args: unknown[]) => mockGetSession(...args),
}))

vi.mock('@/lib/mcp/auth', () => ({
createMcpDeviceLoginApprovalChallenge: (...args: unknown[]) =>
mockCreateMcpDeviceLoginApprovalChallenge(...args),
}))

vi.mock('@/app/(auth)/components/auth-page-header', () => ({
AuthPageHeader: ({
description,
eyebrow,
title,
}: {
description: string
eyebrow: string
title: string
}) => (
<header>
<p>{eyebrow}</p>
<h1>{title}</h1>
<p>{description}</p>
</header>
),
}))

vi.mock('@/components/ui/button', () => ({
Button: ({ children, ...props }: React.ButtonHTMLAttributes<HTMLButtonElement>) => (
<button {...props}>{children}</button>
),
}))

vi.mock('@/app/fonts/inter', () => ({
inter: { className: 'inter' },
}))

vi.mock('@/i18n/navigation', () => ({
redirect: (...args: unknown[]) => mockRedirect(...args),
}))

describe('MCP authorize page', () => {
beforeEach(() => {
vi.clearAllMocks()
vi.resetModules()
mockHeaders.mockResolvedValue(new Headers())
mockGetSessionCookie.mockReturnValue(null)
mockGetSession.mockResolvedValue({ user: { id: 'user-1' } })
mockCreateMcpDeviceLoginApprovalChallenge.mockResolvedValue({
status: 'pending',
approvalToken: 'approval-token',
expiresAt: '2026-06-19T12:00:00.000Z',
})
})

it('renders a confirmation form with a user-bound approval challenge', async () => {
const McpAuthorizePage = (await import('./page')).default

const result = await McpAuthorizePage({
params: Promise.resolve({ locale: 'es' }),
searchParams: Promise.resolve({ code: 'login-code' }),
})
const markup = renderToStaticMarkup(result)

expect(mockCreateMcpDeviceLoginApprovalChallenge).toHaveBeenCalledWith({
code: 'login-code',
userId: 'user-1',
})
expect(markup).toContain('Aprobar clave API personal')
expect(markup).toContain('method="post"')
expect(markup).toContain('action="/api/auth/mcp/authorize"')
expect(markup).toContain('name="approvalToken"')
expect(markup).toContain('value="approval-token"')
})
})
121 changes: 121 additions & 0 deletions apps/tradinggoose/app/[locale]/(auth)/mcp/authorize/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
import { getSessionCookie } from 'better-auth/cookies'
import { headers } from 'next/headers'
import { Button } from '@/components/ui/button'
import { getSession } from '@/lib/auth'
import { createMcpDeviceLoginApprovalChallenge } from '@/lib/mcp/auth'
import { AuthPageHeader } from '@/app/(auth)/components/auth-page-header'
import { inter } from '@/app/fonts/inter'
import { redirect } from '@/i18n/navigation'
import { getPublicCopy } from '@/i18n/public-copy'
import { normalizeLocaleCode } from '@/i18n/utils'

export const dynamic = 'force-dynamic'

type SearchParams = Promise<{
code?: string | string[]
status?: string | string[]
}>

export default async function McpAuthorizePage({
params,
searchParams,
}: {
params: Promise<{ locale: string }>
searchParams: SearchParams
}) {
const [{ locale: routeLocale }, query, requestHeaders] = await Promise.all([
params,
searchParams,
headers(),
])
const locale = normalizeLocaleCode(routeLocale)
const mcpCopy = getPublicCopy(locale).auth.mcp
const code = Array.isArray(query.code) ? query.code[0] : query.code
const rawStatus = Array.isArray(query.status) ? query.status[0] : query.status
const statusCopy =
rawStatus === 'approved'
? mcpCopy.approved
: rawStatus === 'cancelled'
? mcpCopy.cancelled
: rawStatus === 'expired'
? mcpCopy.expired
: rawStatus === 'invalid'
? mcpCopy.invalid
: null
const renderStatus = (copy: { title: string; description: string }) => (
<div className='space-y-8 text-center'>
<AuthPageHeader eyebrow={mcpCopy.eyebrow} title={copy.title} description={copy.description} />
</div>
)

if (statusCopy) {
return renderStatus(statusCopy)
}

if (!code) {
return renderStatus(mcpCopy.invalid)
}

const session = await getSession(requestHeaders)
if (!session?.user?.id) {
return redirect({
href: {
pathname: '/login',
query: {
...(getSessionCookie(requestHeaders) ? { reauth: '1' } : {}),
callbackUrl: `/${locale}/mcp/authorize?code=${encodeURIComponent(code)}`,
},
},
locale,
})
}

const approvalStatus = await createMcpDeviceLoginApprovalChallenge({
code,
userId: session.user.id,
})

if (approvalStatus.status === 'expired') {
return renderStatus(mcpCopy.expired)
}

if (approvalStatus.status === 'approved') {
return renderStatus(mcpCopy.approved)
}

if (approvalStatus.status !== 'pending') {
return renderStatus(mcpCopy.invalid)
}

return (
<div className='space-y-8 text-center'>
<AuthPageHeader
eyebrow={mcpCopy.eyebrow}
title={mcpCopy.confirm.title}
description={mcpCopy.confirm.description}
/>
<form method='post' action='/api/auth/mcp/authorize' className='space-y-3'>
<input type='hidden' name='code' value={code} />
<input type='hidden' name='approvalToken' value={approvalStatus.approvalToken} />
<input type='hidden' name='locale' value={locale} />
<div className='flex flex-col gap-3 sm:flex-row sm:justify-center'>
<Button type='submit' name='action' value='approve' className='text-[15px]'>
{mcpCopy.confirm.approve}
</Button>
<Button
type='submit'
name='action'
value='cancel'
variant='outline'
className='text-[15px]'
>
{mcpCopy.confirm.cancel}
</Button>
</div>
</form>
<p className={`${inter.className} text-muted-foreground text-sm`}>
{mcpCopy.confirm.terminalHint}
</p>
</div>
)
}
15 changes: 7 additions & 8 deletions apps/tradinggoose/app/[locale]/workspace/page.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const mockRedirect = vi.fn((url: string) => {
const mockGetSession = vi.fn()
const mockHeaders = vi.fn()
const mockGetUserWorkspaces = vi.fn()
const mockCreateDefaultWorkspaceForUser = vi.fn()
const mockReadWorkflowAccessContext = vi.fn()

function mockLocalizedRedirect({
Expand Down Expand Up @@ -38,6 +39,7 @@ vi.mock('@/lib/auth', () => ({
}))

vi.mock('@/lib/workspaces/service', () => ({
createDefaultWorkspaceForUser: (...args: unknown[]) => mockCreateDefaultWorkspaceForUser(...args),
getUserWorkspaces: (...args: unknown[]) => mockGetUserWorkspaces(...args),
}))

Expand Down Expand Up @@ -72,6 +74,7 @@ describe('Workspace root page access guard', () => {
},
})
mockGetUserWorkspaces.mockResolvedValue([{ id: 'workspace-1' }])
mockCreateDefaultWorkspaceForUser.mockResolvedValue({ id: 'workspace-created' })
mockReadWorkflowAccessContext.mockResolvedValue(null)
})

Expand Down Expand Up @@ -146,20 +149,16 @@ describe('Workspace root page access guard', () => {

expect(mockGetUserWorkspaces).toHaveBeenCalledWith({
userId: 'user-1',
userName: 'Ada Lovelace',
})
})

it('bootstraps a workspace on the server when the user has none and redirects to it', async () => {
mockGetUserWorkspaces.mockResolvedValue([{ id: 'workspace-bootstrapped' }])
it('repairs authenticated users with no workspace from the workspace entrypoint', async () => {
mockGetUserWorkspaces.mockResolvedValue([])

await expect(renderWorkspacePage('en')).rejects.toThrow(
'redirect:/en/workspace/workspace-bootstrapped/dashboard'
'redirect:/en/workspace/workspace-created/dashboard'
)

expect(mockGetUserWorkspaces).toHaveBeenCalledWith({
userId: 'user-1',
userName: 'Ada Lovelace',
})
expect(mockCreateDefaultWorkspaceForUser).toHaveBeenCalledWith('user-1', 'Ada Lovelace')
})
})
15 changes: 5 additions & 10 deletions apps/tradinggoose/app/[locale]/workspace/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { getSessionCookie } from 'better-auth/cookies'
import { headers } from 'next/headers'
import { getSession } from '@/lib/auth'
import { readWorkflowAccessContext } from '@/lib/workflows/utils'
import { getUserWorkspaces } from '@/lib/workspaces/service'
import { createDefaultWorkspaceForUser, getUserWorkspaces } from '@/lib/workspaces/service'
import { redirect } from '@/i18n/navigation'
import { type LocaleCode, normalizeCallbackUrl, requireCanonicalCallbackPath } from '@/i18n/utils'

Expand Down Expand Up @@ -87,14 +87,9 @@ export default async function WorkspacePage({
}
}

const [workspace] = await getUserWorkspaces({
userId,
userName: session.user.name,
})
const [workspace] = await getUserWorkspaces({ userId })
const targetWorkspace =
workspace ?? (await createDefaultWorkspaceForUser(userId, session.user.name))

if (!workspace) {
throw new Error('Expected workspace bootstrap to return a workspace')
}

return redirect({ href: `/workspace/${workspace.id}/dashboard`, locale })
return redirect({ href: `/workspace/${targetWorkspace.id}/dashboard`, locale })
}
Loading