xuym-codex-collab 0.7.0 → 0.9.0

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.
@@ -1,14 +1,342 @@
1
- :root{color-scheme:dark;--bg:#080e14;--surface:#101923;--surface-raised:#15212c;--line:#243440;--text:#e8f1f4;--muted:#9baeb9;--accent:#7cebc3;--accent-dark:#0a3b30;--radius:18px;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC",sans-serif;color:var(--text);background:var(--bg);font-synthesis:none}
2
- *{box-sizing:border-box}body{margin:0;min-height:100vh;background:radial-gradient(ellipse at 50% 0,#102b313d,transparent 65%)}body::before{content:"";position:fixed;inset:0;pointer-events:none;background-image:linear-gradient(#b6e6df04 1px,transparent 1px),linear-gradient(90deg,#b6e6df04 1px,transparent 1px);background-size:64px 64px;z-index:-1}.ambient{position:fixed;inset:0;overflow:hidden;pointer-events:none;z-index:-1}.ambient i{position:absolute;width:480px;height:480px;border-radius:50%;background:radial-gradient(circle,#25be9e12,transparent 70%);top:-170px;left:8%;animation:ambient-drift 24s ease-in-out infinite alternate}.ambient i+i{width:560px;height:560px;background:radial-gradient(circle,#497bdf0d,transparent 70%);top:10%;left:auto;right:-180px;animation-delay:-12s}
3
- header{position:relative;border-bottom:1px solid #2434409c;display:flex;justify-content:space-between;align-items:center;gap:20px;padding:20px max(24px,calc((100vw - 1120px)/2));font-size:13px;background:#0c141de8}.brand{display:inline-flex;align-items:center;gap:12px;font-weight:730;letter-spacing:-.4px;color:var(--text);text-decoration:none;font-size:17px;white-space:nowrap}.brand-mark{display:grid;place-items:center;width:32px;height:32px;background:linear-gradient(135deg,#9bf5d5,#50bdb7);color:#0a2521;font-weight:850;border-radius:10px;box-shadow:0 0 26px #65d8ba18}.workspace-label{display:flex;align-items:center;gap:9px;color:var(--muted)}.status-dot{width:6px;height:6px;border-radius:50%;background:var(--accent);box-shadow:0 0 0 4px #7cebc30d}
4
- main{max-width:1120px;margin:58px auto 0;padding:0 24px}.hero{max-width:760px;animation:enter-view .55s ease-out backwards}.eyebrow{font-size:10px;font-weight:700;letter-spacing:2.6px;color:var(--accent);margin:0 0 14px;line-height:1.6}h1{font-size:clamp(30px,4.5vw,46px);font-weight:720;line-height:1.28;letter-spacing:-1.4px;margin:0 0 18px}h1 span{color:var(--accent)}h2{font-size:23px;letter-spacing:-.5px;line-height:1.4;margin:0}h3{font-size:16px;margin:30px 0 14px;line-height:1.5}h4{font-size:16px;margin:0;line-height:1.6;overflow-wrap:anywhere}p{line-height:1.8}.intro,.muted{color:var(--muted)}.intro{font-size:15px;margin:0}.muted{font-size:13px}.warning-text{color:#f1bd83}
5
- nav{display:flex;gap:8px;margin:32px 0 26px;flex-wrap:wrap}button,a.secondary{font:inherit;font-size:13px;font-weight:600;background:var(--accent);color:#092c24;border:1px solid transparent;border-radius:9px;padding:11px 17px;cursor:pointer;line-height:1.5;position:relative;transition:transform .18s ease,background-color .18s ease,border-color .18s ease,box-shadow .18s ease;touch-action:manipulation}button:hover{transform:translateY(-2px);background:#a4f5d9;box-shadow:0 5px 20px #7cebc312}button:active{transform:translateY(0) scale(.98)}button:disabled{opacity:.5;cursor:wait;transform:none;box-shadow:none}nav button,.secondary,a.secondary{background:#111c26;color:#c3d3dc;border:1px solid var(--line)}nav button:hover,.secondary:hover{background:#1b2b37;border-color:#456273;box-shadow:none}nav button[aria-current=page]{background:#1c302e;border-color:#497c6c;color:#b9f5df}a{color:var(--accent);text-underline-offset:3px}a.secondary{display:inline-block;text-decoration:none}button:focus-visible,a:focus-visible,summary:focus-visible{outline:2px solid var(--accent);outline-offset:4px}.back-button{margin:0 0 26px;background:transparent;border-color:transparent;color:var(--muted);padding:5px 0}.back-button:hover{background:transparent;border-color:transparent;color:var(--accent);box-shadow:none}
6
- section{background:linear-gradient(145deg,#111c26,#0e1720);border:1px solid var(--line);border-radius:var(--radius);padding:30px;box-shadow:0 16px 55px #00000012}section:not([hidden]){animation:enter-view .35s cubic-bezier(.2,.7,.2,1) backwards}[hidden]{display:none!important}section>p{font-size:14px;color:var(--muted)}.section-heading{display:flex;justify-content:space-between;align-items:center;gap:16px;margin:0 0 20px}.section-heading .eyebrow{margin:0 0 8px;font-size:9px}.section-heading h3{margin:0}.robot-heading{margin-top:30px}
7
- .entry-options{display:grid;grid-template-columns:repeat(2,minmax(0,1fr));gap:16px;margin:0 0 18px}.entry-options button{overflow:hidden;text-align:left;padding:24px 26px;font-size:18px;border-radius:13px;border:1px solid #345b50;background:linear-gradient(120deg,#1b3933,#172a2b);color:#dcfff0}.entry-options button::after{content:"↗";position:absolute;right:22px;top:20px;font-size:20px;color:#87c9b4;transition:transform .2s}.entry-options button:hover::after{transform:translate(3px,-3px)}.entry-options button+button{background:linear-gradient(120deg,#1b2939,#17202f);border-color:#33455e;color:#dfebff}.entry-options button+button::after{color:#9aaed6}.entry-options small{display:block;margin:10px 15px 0 0;font-size:12px;font-weight:400;color:#a9c2b8;line-height:1.8}.entry-options button+button small{color:#a8b5cc}#startup-status{font-size:12px;margin:0 0 30px}
8
- .project-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,285px),1fr));gap:16px}.project-card{display:flex;flex-direction:column;align-items:stretch;justify-content:space-between;gap:22px;padding:24px;border:1px solid #2a3d49;border-radius:14px;background:linear-gradient(150deg,#172530,#111c26);overflow:hidden;position:relative;transition:border-color .25s,box-shadow .25s}.project-card::after{content:"";position:absolute;inset:0;border-radius:inherit;border-top:1px solid #b1efdd35;pointer-events:none}.project-card:hover{border-color:#4b7f72;box-shadow:0 8px 24px #00000020}.project-card-info{min-width:0}.project-icon{display:grid;place-items:center;width:42px;height:42px;border:1px solid #406659;border-radius:12px;background:#1c3932;color:#a8f2d5;font-size:20px;font-weight:650;margin-bottom:22px}.project-card h3{font-size:19px;line-height:1.5;margin:0 0 7px;overflow-wrap:anywhere}.project-card p{color:var(--muted);font-size:12px;margin:0 0 18px;overflow-wrap:anywhere}.project-card-info>span:last-child{color:#a9bfca;font-size:12px}.project-card>button{align-self:flex-start;background:transparent;color:var(--accent);border-color:#314c46;padding:8px 13px}.project-card>button:hover{background:#7cebc30b;border-color:#608f7f}.project-card,.robot-card{animation:enter-card .4s cubic-bezier(.2,.7,.2,1) backwards;animation-delay:calc(var(--order,0)*45ms)}
9
- .repository-path,#profile-repo,#reset-target,#invite-remote{overflow-wrap:anywhere;color:var(--muted);font-size:13px}.project-summary{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:1px;border:1px solid var(--line);border-radius:12px;background:var(--line);overflow:hidden;margin:25px 0 15px}.summary-item{background:#111e28;padding:19px 22px;display:flex;flex-direction:column;gap:8px;min-width:0}.summary-item strong{font-size:24px;font-weight:650;letter-spacing:-.5px;overflow-wrap:anywhere}.summary-item:last-child strong{font-size:20px;line-height:1.5}.summary-item span{font-size:11px;color:var(--muted)}.robot-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,285px),1fr));gap:15px}.robot-card{border:1px solid var(--line);border-radius:13px;padding:22px;background:#111e28;min-width:0}.robot-card.is-mine{border-color:#365f51;background:linear-gradient(145deg,#162923,#122028)}.robot-title{display:flex;justify-content:space-between;gap:10px;align-items:center}.robot-card>p{margin:9px 0 0;font-size:12px;color:var(--muted)}.robot-connection{border-top:1px solid var(--line);padding-top:18px;margin-top:20px}.robot-connection .repository-path{margin:12px 0 16px;font-size:11px}.robot-connection button{padding:8px 13px;font-size:12px}.badge{display:inline-flex;gap:7px;align-items:center;font-size:11px;font-weight:500;color:var(--accent);background:#1a3b30;padding:5px 9px;border-radius:6px;white-space:nowrap}.mine-badge{border:1px solid #376a54;flex-shrink:0}.pending{color:#f0c27e;background:#3a2e1c}.ready-badge::before{content:"";height:5px;width:5px;border-radius:50%;background:var(--accent);animation:status-pulse 2.8s ease-in-out infinite}
10
- form{display:grid;gap:18px;margin:25px 0}form,label,fieldset,details,input,select{min-width:0}label{display:grid;gap:9px;font-size:13px;color:#c7d5dd}input,select{font:inherit;font-size:14px;padding:12px 14px;border:1px solid #31424f;border-radius:8px;width:100%;color:var(--text);background:#0c151e;transition:border-color .18s,box-shadow .18s}input::placeholder{color:#708592}input:focus,select:focus{outline:none;border-color:#6dc6a8;box-shadow:0 0 0 3px #7cebc310}input[type=file]{font-size:12px}input[type=file]::file-selector-button{border:1px solid #3a4f5e;border-radius:5px;background:#1d2c38;color:var(--text);padding:6px 10px;margin-right:12px}.row{display:flex;gap:20px;align-items:center}.row>*{flex:1;min-width:0}.row>button{flex:initial}.checkbox{display:flex;align-items:flex-start;line-height:1.7}.checkbox input{width:auto;margin:4px 0 0;accent-color:var(--accent)}fieldset{border:1px solid var(--line);border-radius:11px;padding:20px;margin:0 0 16px;display:grid;gap:16px}legend{font-weight:600;padding:0 8px;color:#d5e4eb}pre{background:#09131b;border:1px solid var(--line);padding:18px;border-radius:10px;white-space:pre-wrap;overflow-wrap:anywhere;color:#c3e5d6;font:12px/1.8 ui-monospace,SFMono-Regular,monospace}details{margin:24px 0}summary{cursor:pointer;font-size:14px;font-weight:550;line-height:1.8;color:#c3d4dd}details[open]>summary{margin-bottom:18px;color:var(--accent)}.card:not(.project-card),.check{padding:17px 0;border-bottom:1px solid var(--line);display:flex;gap:14px;justify-content:space-between;align-items:center}.card p{margin:4px 0;font-size:12px;overflow-wrap:anywhere}.card:not(.project-card)>div{min-width:0}.check{font-size:13px}.check .badge{flex-shrink:0}.manage-actions{display:flex;gap:10px;flex-wrap:wrap}.danger{background:#2a1b20;border:1px solid #6a3a42;color:#f3a7a7}.danger:hover{background:#38212a;border-color:#a6656d}.manage-actions .danger{box-shadow:none}#notice{padding:14px 18px;border:1px solid #725035;background:#30241a;color:#f5cfa9;border-radius:10px;margin:20px 0;font-size:13px;line-height:1.8}#reset-effects{line-height:1.9;padding-left:24px;font-size:14px}#reset-verification{padding:18px;background:#142822;border:1px solid #2a4b3e;border-radius:10px}
11
- #setup-steps{display:flex;flex-wrap:wrap;gap:9px;list-style:none;padding:0;margin:24px 0}#setup-steps li{font-size:11px;border:1px solid var(--line);border-radius:7px;padding:9px 12px;color:#8fa2ad}#setup-steps .done{color:#99e9bf;background:#153026;border-color:#315d45}#setup-steps .active{color:#f0c27e;background:#30271a;border-color:#6c5330}#next-step{padding:16px 18px;background:#142b26;border:1px solid #2b5144;border-radius:10px;color:#bbe6d3;line-height:1.8;font-size:14px}#binding h3{color:#b0f0d6}#delivery-panel{padding:22px;background:#13241f;border:1px solid #365c4b;border-radius:12px;margin-top:22px}#delivery-panel h3{margin-top:0}#delivery-panel button{margin:6px 6px 6px 0}.assignment details{margin:0}.assignment>button{justify-self:start;background:transparent;color:var(--muted);border-color:var(--line)}#assignment-rows{display:grid;gap:14px}#assignment-rows fieldset{margin:0}#diagnostic-result p{font-size:13px;line-height:1.8}#diagnostic-actions{margin:20px 0}footer{text-align:center;font-size:11px;color:#7e939f;padding:30px 24px 40px;line-height:1.8}
12
- @keyframes enter-view{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}@keyframes enter-card{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:translateY(0)}}@keyframes ambient-drift{from{transform:translate3d(0,0,0)}to{transform:translate3d(90px,65px,0)}}@keyframes status-pulse{0%,100%{opacity:1}50%{opacity:.4}}html[data-page-hidden=true] *,html[data-page-hidden=true] *::before,html[data-page-hidden=true] *::after{animation-play-state:paused!important}
13
- @media(max-width:640px){header{padding:17px 20px}.brand{font-size:15px}.workspace-label{font-size:11px;gap:7px}.brand-mark{width:28px;height:28px}main{margin:34px auto 0;padding:0 16px}h1{letter-spacing:-.8px}h1 span{display:block}.hero .eyebrow{font-size:9px}.intro{font-size:13px}nav{gap:7px;margin:25px 0 20px}nav button{font-size:11px;padding:8px 10px}section{padding:22px 18px;border-radius:14px}.entry-options{grid-template-columns:1fr;gap:12px}.entry-options button{font-size:16px;padding:20px}.entry-options small{margin-top:7px}.section-heading{align-items:flex-start;gap:12px}.section-heading h2{font-size:21px}.section-heading>button{font-size:11px;white-space:nowrap}.robot-heading{flex-direction:column;align-items:stretch}.robot-heading .manage-actions{justify-content:flex-start}.project-summary{margin-top:20px}.summary-item{padding:16px 12px}.summary-item strong{font-size:22px}.summary-item:last-child strong{font-size:15px;line-height:1.9}.summary-item span{font-size:10px}.row{flex-direction:column;align-items:stretch;gap:16px}.row>button{align-self:flex-start}.card:not(.project-card){align-items:flex-start;flex-wrap:wrap}.project-card{padding:22px}.project-grid,.robot-grid{grid-template-columns:minmax(0,1fr)}.manage-actions button{font-size:12px}#setup-steps{gap:7px}#setup-steps li{flex:1 1 42%;padding:9px}.ambient i{width:300px;height:300px}.ambient i+i{width:340px;height:340px}fieldset{padding:16px}footer{font-size:10px}}
14
- @media(prefers-reduced-motion:reduce){*,*::before,*::after{animation:none!important;transition:none!important;scroll-behavior:auto!important}button:hover,button:active{transform:none}.entry-options button:hover::after{transform:none}}
1
+ :root { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", sans-serif; -webkit-font-smoothing: antialiased; text-rendering: optimizeLegibility; font-synthesis: none; }
2
+ * { box-sizing: border-box; }
3
+ [hidden] { display: none !important; }
4
+ body {
5
+ --bg: #faf9f6; --surface: #fffefa; --ink: #263c32; --muted: #879187; --line: #e4e8df;
6
+ --accent: #355d49; --on-accent: #fff; --wash: #eaf0e6; --hover: #f1f3eb; --shadow: #355d4909;
7
+ color-scheme: light; margin: 0; background: var(--bg); color: var(--ink); min-height: 100dvh; display: flex; flex-direction: column;
8
+ }
9
+ body[data-theme="studio"] { --bg: #f0f4ef; --surface: #f8fbf6; --ink: #2c4338; --muted: #809181; --line: #d8e2d6; --accent: #426c50; --wash: #e0eadd; --hover: #e9f0e5; }
10
+ body[data-theme="night"] { color-scheme: dark; --bg: #131b19; --surface: #1a2420; --ink: #e9eee3; --muted: #82958b; --line: #2e3d34; --accent: #c3d5b0; --on-accent: #23372a; --wash: #2b3b2f; --hover: #1d2b22; --shadow: #0000000b; }
11
+ button, input { font: inherit; }
12
+ a { color: inherit; text-decoration: none; }
13
+ button { color: inherit; border: 0; background: none; cursor: pointer; }
14
+ button, a { -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
15
+ button:focus-visible, a:focus-visible, input:focus-visible { outline: 2px solid var(--accent); outline-offset: 5px; }
16
+ button:disabled { cursor: default; }
17
+ h1, p { margin: 0; }
18
+ h1:focus { outline: none; }
19
+ .icon { width: 20px; height: 20px; flex-shrink: 0; }
20
+ .masthead { display: flex; align-items: center; justify-content: space-between; padding: 30px 44px; gap: 16px; }
21
+ .brand { display: inline-flex; align-items: center; gap: 10px; font-size: 14px; letter-spacing: -.4px; font-weight: 550; }
22
+ .brand-mark { display: inline-grid; place-items: center; width: 27px; height: 27px; font: 26px/1 sans-serif; color: var(--accent); }
23
+ .preview-label { font-size: 10px; color: var(--muted); letter-spacing: 1px; }
24
+ main { width: 100%; flex: 1; padding: 50px 24px 66px; display: flex; justify-content: center; align-items: flex-start; }
25
+ .scene { width: 100%; max-width: 536px; }
26
+ .home, .project-scene, .setup-scene, .success-scene { position: relative; }
27
+ .intro { text-align: center; }
28
+ h1 { font-size: 35px; line-height: 1.4; letter-spacing: -1.4px; font-weight: 500; overflow-wrap: anywhere; }
29
+ .intro > p { margin-top: 13px; font-size: 13px; color: var(--muted); line-height: 1.9; letter-spacing: .15px; }
30
+ .scene-art { display: grid; place-items: center; width: 88px; height: 88px; position: relative; margin: 0 auto 25px; --art-wash: var(--wash); --art-ink: var(--accent); }
31
+ .art-halo { position: absolute; inset: -7px; border-radius: 50%; background: radial-gradient(circle, var(--art-wash), transparent 72%); opacity: .9; }
32
+ .art-tile { position: relative; display: grid; place-items: center; width: 59px; height: 59px; color: var(--art-ink); background: var(--surface); border: 1px solid var(--line); border-radius: 18px; box-shadow: 0 4px 8px var(--shadow), 0 14px 28px var(--shadow); transform: rotate(-9deg); animation: settle-tile 650ms cubic-bezier(.2,.75,.2,1) both; }
33
+ .art-tile .icon { width: 29px; height: 29px; }
34
+ .scene-art.welcome { width: 110px; height: 97px; margin-bottom: 26px; }
35
+ .welcome .art-tile { transform: translate(-11px, 0) rotate(-12deg); width: 62px; height: 62px; }
36
+ .art-small { position: absolute; bottom: 4px; right: 4px; display: grid; place-items: center; width: 40px; height: 40px; border-radius: 13px; background: var(--wash); color: var(--accent); border: 1px solid var(--line); transform: rotate(10deg); animation: arrive-small 750ms cubic-bezier(.2,.75,.2,1) both; }
37
+ .art-small .icon { width: 22px; height: 22px; }
38
+ .art-spark { position: absolute; width: 5px; height: 5px; background: var(--accent); border-radius: 50%; top: 12px; right: 4px; opacity: .5; animation: little-spark 1s ease-out both; }
39
+ .project-list { display: flex; flex-direction: column; gap: 11px; margin-top: 38px; }
40
+ .project-entry { display: flex; align-items: center; padding: 21px 21px; gap: 16px; border: 1px solid var(--line); background: var(--surface); border-radius: 16px; transition: transform 230ms cubic-bezier(.2,.75,.2,1), background-color 180ms, border-color 180ms, box-shadow 230ms; animation: arrive-row 450ms ease-out calc(var(--order) * 65ms) both; }
41
+ .project-entry:hover { transform: translateY(-3px); background: var(--hover); border-color: color-mix(in srgb, var(--accent) 35%, var(--line)); box-shadow: 0 10px 20px var(--shadow); }
42
+ .project-icon { display: inline-grid; place-items: center; width: 43px; height: 43px; border-radius: 13px; background: var(--wash); color: var(--accent); flex-shrink: 0; }
43
+ .project-icon .icon { width: 22px; height: 22px; }
44
+ .blue { --art-wash: #e7edf5; --art-ink: #6682a0; }
45
+ .sand { --art-wash: #f1e9db; --art-ink: #a78a64; }
46
+ .project-icon.blue { color: #6682a0; background: #eaf0f6; }
47
+ .project-icon.sand { color: #a78a64; background: #f4eee3; }
48
+ body[data-theme="night"] .project-icon.blue { color: #a6bdcf; background: #293a41; }
49
+ body[data-theme="night"] .project-icon.sand { color: #cfbc9b; background: #3c372b; }
50
+ .project-copy, .agent-copy { min-width: 0; flex: 1; }
51
+ .project-copy strong { display: block; font-weight: 500; font-size: 17px; letter-spacing: -.4px; overflow-wrap: anywhere; }
52
+ .project-copy > span { display: block; font-size: 11px; color: var(--muted); margin-top: 7px; line-height: 1.5; }
53
+ .entry-arrow { display: inline-flex; color: var(--muted); opacity: .5; transition: transform 220ms, opacity 220ms; }
54
+ .entry-arrow .icon { width: 17px; height: 17px; }
55
+ .project-entry:hover .entry-arrow { transform: translateX(3px); opacity: 1; color: var(--accent); }
56
+ .home-actions, .project-actions { display: flex; align-items: center; justify-content: center; gap: 24px; margin-top: 29px; }
57
+ .button { display: inline-flex; align-items: center; justify-content: center; gap: 9px; padding: 13px 21px; min-height: 45px; border-radius: 30px; font-size: 12px; letter-spacing: .2px; font-weight: 500; transition: transform 180ms, opacity 180ms, box-shadow 180ms; }
58
+ .button .icon { width: 16px; height: 16px; }
59
+ .button.primary { background: var(--accent); color: var(--on-accent); }
60
+ .button.primary:hover:enabled, a.button.primary:hover { transform: translateY(-2px); box-shadow: 0 6px 15px var(--shadow); }
61
+ .button:active:enabled { transform: scale(.98); }
62
+ .button:disabled { opacity: .28; }
63
+ .quiet-button { display: inline-flex; align-items: center; justify-content: center; gap: 6px; font-size: 11px; color: var(--muted); padding: 9px 0; transition: color 150ms; }
64
+ .quiet-button:hover { color: var(--accent); }
65
+ .quiet-button .icon { width: 13px; height: 13px; }
66
+ .demo-footer { padding: 20px 44px 25px; display: flex; justify-content: space-between; gap: 20px; align-items: center; }
67
+ .demo-footer > span { color: var(--muted); font-size: 9px; opacity: .7; }
68
+ .theme-picker { display: flex; gap: 13px; }
69
+ .theme-picker button { display: inline-flex; align-items: center; gap: 5px; font-size: 9px; color: var(--muted); padding: 6px 0; opacity: .55; }
70
+ .theme-picker button[aria-pressed="true"] { color: var(--ink); opacity: 1; }
71
+ .theme-picker button:hover { opacity: 1; }
72
+ .theme-picker i { width: 7px; height: 7px; border-radius: 50%; border: 1px solid #c4cbbd; background: #faf9f6; }
73
+ .theme-picker [data-theme-choice="studio"] i { background: #bac9b5; border-color: #a8bba4; }
74
+ .theme-picker [data-theme-choice="night"] i { background: #344a3e; border-color: #4c6353; }
75
+ .back-link { display: inline-flex; align-items: center; gap: 7px; font-size: 11px; color: var(--muted); padding: 6px 0; margin: 0 0 24px; }
76
+ .back-link:hover { color: var(--accent); }
77
+ .back-link .icon { width: 14px; height: 14px; }
78
+ .project-scene .scene-art { margin-top: 0; margin-bottom: 18px; }
79
+ .project-scene h1 { font-size: 31px; letter-spacing: -1px; }
80
+ .agent-list { margin-top: 34px; }
81
+ .agent-row { display: flex; align-items: center; gap: 14px; border-bottom: 1px solid var(--line); padding: 22px 4px; animation: arrive-row 400ms ease-out calc(var(--order) * 60ms) both; }
82
+ .agent-row:last-child { border-bottom: 0; }
83
+ .agent-icon { display: inline-grid; place-items: center; color: var(--muted); width: 40px; height: 40px; }
84
+ .agent-icon.owned { border-radius: 12px; background: var(--wash); color: var(--accent); }
85
+ .agent-icon .icon { width: 23px; height: 23px; }
86
+ .agent-copy strong { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; font-size: 14px; font-weight: 500; }
87
+ .agent-copy > span { display: block; font-size: 10px; color: var(--muted); margin-top: 6px; }
88
+ .mine-tag { font-size: 8px; background: var(--wash); color: var(--accent); padding: 3px 6px; border-radius: 4px; font-weight: 400; }
89
+ .agent-action { display: inline-flex; padding: 10px 0 10px 8px; color: var(--muted); }
90
+ .agent-action .icon { width: 14px; height: 14px; }
91
+ .small-link { display: inline-flex; align-items: center; gap: 4px; font-size: 10px; color: var(--accent); }
92
+ .small-link .icon { width: 13px; height: 13px; }
93
+ .disclosure { margin-top: 24px; display: grid; grid-template-columns: auto 1fr; gap: 10px 18px; color: var(--muted); padding: 17px 20px; background: var(--wash); border-radius: 10px; font-size: 10px; }
94
+ .disclosure code { font: 10px/1.6 ui-monospace, monospace; overflow-wrap: anywhere; color: var(--ink); }
95
+ /* One task at a time. The surrounding page stays quiet during setup. */
96
+ .setup-scene { max-width: 440px; margin: 0 auto; }
97
+ .setup-scene .back-link { margin-bottom: 28px; }
98
+ .step-progress { position: absolute; right: 0; top: 13px; display: flex; gap: 5px; }
99
+ .step-progress span { height: 3px; width: 19px; background: var(--line); border-radius: 9px; }
100
+ .step-progress span.filled { background: var(--accent); }
101
+ .setup-scene .intro h1 { font-size: 30px; letter-spacing: -1.1px; }
102
+ .setup-scene .intro p { font-size: 12px; }
103
+ .setup-scene .scene-art { margin-bottom: 23px; }
104
+ .step-content { margin-top: 34px; }
105
+ .pick-area { width: 100%; display: flex; align-items: center; flex-direction: column; justify-content: center; gap: 13px; min-height: 173px; padding: 27px 20px; background: var(--surface); border: 1px dashed var(--line); border-radius: 17px; transition: border-color 180ms, background-color 180ms; }
106
+ .pick-area:hover { background: var(--hover); border-color: var(--accent); }
107
+ .pick-area > .icon { width: 28px; height: 28px; color: var(--accent); margin-bottom: 1px; }
108
+ .pick-area strong { font-size: 13px; font-weight: 500; overflow-wrap: anywhere; }
109
+ .pick-area > span:last-child { font-size: 10px; color: var(--muted); line-height: 1.7; }
110
+ .pick-area.selected { background: var(--wash); border-style: solid; border-color: color-mix(in srgb, var(--accent) 20%, var(--line)); }
111
+ .selection-check { display: inline-grid; place-items: center; width: 29px; height: 29px; border-radius: 50%; background: var(--accent); color: var(--on-accent); }
112
+ .selection-check .icon { width: 16px; height: 16px; }
113
+ .step-actions { display: flex; flex-direction: column; align-items: center; margin-top: 30px; gap: 18px; }
114
+ .continue-button { min-width: 158px; flex-direction: row-reverse; }
115
+ .step-count { color: var(--muted); font: 9px ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: 2px; opacity: .65; }
116
+ .field { display: flex; flex-direction: column; gap: 9px; font-size: 11px; color: var(--muted); }
117
+ .field + .field, .pick-area + .field { margin-top: 21px; }
118
+ .field input { min-width: 0; width: 100%; height: 47px; border: 1px solid var(--line); background: var(--surface); padding: 13px 15px; border-radius: 10px; color: var(--ink); font-size: 12px; box-shadow: none; }
119
+ .field input::placeholder { color: var(--muted); }
120
+ .help-link { display: block; margin: 16px auto 0; font-size: 10px; color: var(--muted); padding: 5px; }
121
+ .help-link:hover { color: var(--accent); }
122
+ .help-note { font-size: 11px; color: var(--muted); line-height: 1.9; padding: 15px 18px; border-radius: 10px; background: var(--wash); margin-top: 12px; }
123
+ .selected-project { display: flex; align-items: center; gap: 13px; padding: 20px; background: var(--wash); border-radius: 14px; margin-bottom: 24px; }
124
+ .selected-project > div { min-width: 0; }
125
+ .selected-project strong { display: block; font-size: 14px; font-weight: 500; }
126
+ .selected-project div > span { display: block; font: 9px/1.6 ui-monospace, monospace; color: var(--muted); margin-top: 6px; overflow-wrap: anywhere; }
127
+ .selected-project > .selection-check { margin-left: auto; width: 23px; height: 23px; flex-shrink: 0; }
128
+ .selected-project > .selection-check .icon { width: 13px; }
129
+ .binding-illustration { display: flex; align-items: center; justify-content: center; padding: 13px 0 28px; }
130
+ .binding-node { display: grid; place-items: center; width: 54px; height: 54px; border-radius: 17px; background: var(--surface); border: 1px solid var(--line); color: var(--accent); }
131
+ .binding-node .icon { width: 27px; height: 27px; }
132
+ .codex-node { font: 32px/1 sans-serif; }
133
+ .binding-line { display: flex; gap: 8px; padding: 0 20px; }
134
+ .binding-line i { width: 4px; height: 4px; border-radius: 50%; background: var(--accent); opacity: .25; animation: connect-dot 1.8s ease-in-out 3 both; }
135
+ .binding-line i:nth-child(2) { animation-delay: .2s; }
136
+ .binding-line i:nth-child(3) { animation-delay: .4s; }
137
+ .binding-caption { text-align: center; font-size: 11px; color: var(--muted); line-height: 1.9; }
138
+ .command-preview { padding: 17px; margin-top: 13px; background: var(--wash); border-radius: 10px; }
139
+ .command-preview code { font: 11px/1.8 ui-monospace, "PingFang SC", monospace; overflow-wrap: anywhere; }
140
+ .success-scene { text-align: center; padding-top: 40px; }
141
+ .success .art-tile { background: var(--accent); color: var(--on-accent); border: 0; border-radius: 50%; transform: none; animation: success-stamp 550ms cubic-bezier(.2,.9,.3,1.2) both; }
142
+ .success-project { display: inline-flex; align-items: center; text-align: left; gap: 13px; margin: 36px auto 32px; padding: 18px 23px; background: var(--wash); border-radius: 15px; max-width: 100%; }
143
+ .success-project > div { min-width: 0; }
144
+ .success-project strong { display: block; font-size: 15px; font-weight: 500; overflow-wrap: anywhere; }
145
+ .success-project div > span { display: block; font-size: 10px; margin-top: 7px; color: var(--muted); }
146
+ .success-scene > .button { display: flex; margin: 0 auto; width: max-content; }
147
+ .success-scene > .quiet-button { display: flex; margin: 15px auto 0; width: max-content; }
148
+ #toast { position: fixed; left: 50%; bottom: 30px; transform: translateX(-50%); width: max-content; max-width: calc(100vw - 32px); color: var(--ink); background: var(--surface); border: 1px solid var(--line); padding: 14px 20px; box-shadow: 0 8px 30px var(--shadow); border-radius: 12px; font-size: 11px; z-index: 3; }
149
+ @keyframes settle-tile { from { opacity: 0; translate: 0 10px; rotate: -8deg; } to { opacity: 1; translate: 0 0; rotate: 0deg; } }
150
+ @keyframes arrive-small { from { opacity: 0; translate: -8px -9px; rotate: -10deg; } to { opacity: 1; translate: 0 0; rotate: 0deg; } }
151
+ @keyframes little-spark { from { opacity: 0; transform: scale(.3); } to { opacity: .5; transform: scale(1); } }
152
+ @keyframes arrive-row { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
153
+ @keyframes connect-dot { 0%, 100% { opacity: .25; transform: scale(.8); } 40%, 60% { opacity: 1; transform: scale(1.2); } }
154
+ @keyframes success-stamp { from { opacity: 0; transform: scale(.7) rotate(-15deg); } to { opacity: 1; transform: scale(1) rotate(0); } }
155
+ html[data-page-hidden="true"] *, html[data-page-hidden="true"] *::before, html[data-page-hidden="true"] *::after { animation-play-state: paused !important; }
156
+ @media (min-height: 950px) and (min-width: 700px) { main { padding-top: 80px; } }
157
+ @media (max-width: 600px) {
158
+ .masthead { padding: 24px; }
159
+ .brand { font-size: 13px; gap: 8px; }
160
+ .brand-mark { font-size: 24px; width: 24px; }
161
+ .preview-label { font-size: 9px; }
162
+ main { padding: 38px 24px 52px; }
163
+ h1 { font-size: 30px; letter-spacing: -1.2px; }
164
+ .intro > p { margin-top: 12px; font-size: 12px; }
165
+ .scene-art.welcome { margin-bottom: 26px; }
166
+ .project-list { margin-top: 30px; gap: 11px; }
167
+ .project-entry { padding: 20px 16px; gap: 12px; border-radius: 15px; }
168
+ .project-icon { width: 38px; height: 38px; border-radius: 12px; }
169
+ .project-icon .icon { width: 20px; height: 20px; }
170
+ .project-copy strong { font-size: 15px; letter-spacing: -.4px; }
171
+ .project-copy > span { font-size: 10px; margin-top: 6px; }
172
+ .entry-arrow .icon { width: 15px; height: 15px; }
173
+ .home-actions { flex-direction: column; gap: 10px; margin-top: 26px; }
174
+ .button { min-height: 45px; font-size: 12px; padding-left: 23px; padding-right: 23px; }
175
+ .demo-footer { flex-direction: column-reverse; gap: 15px; padding: 8px 24px 24px; }
176
+ .demo-footer > span { font-size: 8px; }
177
+ .theme-picker { gap: 20px; }
178
+ .theme-picker button { font-size: 9px; }
179
+ .back-link { margin-bottom: 24px; }
180
+ .project-scene h1 { font-size: 25px; }
181
+ .project-scene .intro p { font-size: 11px; }
182
+ .agent-list { margin-top: 25px; }
183
+ .agent-row { padding: 20px 0; gap: 10px; }
184
+ .agent-copy strong { font-size: 13px; }
185
+ .project-actions { flex-direction: column; gap: 8px; margin-top: 28px; }
186
+ .disclosure { grid-template-columns: 1fr; gap: 8px; }
187
+ .setup-scene .intro h1 { font-size: 26px; letter-spacing: -.9px; }
188
+ .setup-scene .intro p { font-size: 11px; max-width: 285px; margin-left: auto; margin-right: auto; }
189
+ .setup-scene .back-link { margin-bottom: 24px; }
190
+ .setup-scene .scene-art { margin-bottom: 19px; }
191
+ .step-content { margin-top: 28px; }
192
+ .pick-area { min-height: 165px; border-radius: 14px; }
193
+ .step-actions { margin-top: 25px; }
194
+ .selected-project { padding: 17px 15px; gap: 10px; }
195
+ .selected-project strong { font-size: 13px; }
196
+ .selected-project div > span { font-size: 8px; }
197
+ .success-scene { padding-top: 35px; }
198
+ .success-project { padding: 17px; }
199
+ .success-project strong { font-size: 14px; }
200
+ .success-project div > span { font-size: 9px; }
201
+ }
202
+ @media (max-width: 360px) {
203
+ .masthead { padding: 22px 20px; }
204
+ main { padding: 28px 20px 45px; }
205
+ h1 { font-size: 27px; }
206
+ .project-entry { gap: 9px; padding: 19px 13px; }
207
+ .project-copy strong { font-size: 13px; }
208
+ .project-copy > span { font-size: 9px; }
209
+ .project-icon { width: 34px; height: 36px; border-radius: 10px; }
210
+ .entry-arrow .icon { width: 13px; height: 13px; }
211
+ .setup-scene .intro h1 { font-size: 24px; }
212
+ }
213
+ @media (prefers-reduced-motion: reduce) {
214
+ *, *::before, *::after { animation: none !important; transition: none !important; scroll-behavior: auto !important; }
215
+ }
216
+
217
+ /* Live onboarding uses the same quiet layout as the design preview. */
218
+ body { --muted: #6e7d73; }
219
+ body[data-theme="studio"] { --muted: #687d6d; }
220
+ body[data-theme="night"] { --muted: #a1b1a7; }
221
+ main { flex-direction: column; justify-content: flex-start; align-items: center; }
222
+ main > section { width: 100%; }
223
+ h1, h2, h3, h4, p { overflow-wrap: anywhere; }
224
+ h2, h3, h4 { font-weight: 500; }
225
+ h2 { font-size: 26px; }
226
+ h3 { font-size: 16px; margin: 26px 0 12px; }
227
+ h4 { margin: 0; font-size: 14px; }
228
+ p { font-size: 12px; line-height: 1.85; }
229
+ .workspace-label { color: var(--muted); font-size: 11px; letter-spacing: .8px; }
230
+ .muted { color: var(--muted); font-size: 11px; }
231
+ #notice { width: 100%; max-width: 536px; padding: 14px 18px; margin: 0 auto 28px; border: 1px solid var(--line); border-radius: 12px; color: var(--ink); background: var(--wash); font-size: 12px; line-height: 1.8; overflow-wrap: anywhere; }
232
+ button, input, select, textarea { font: inherit; }
233
+ input, select, textarea { min-width: 0; width: 100%; border: 1px solid var(--line); background: var(--surface); padding: 13px 14px; border-radius: 10px; color: var(--ink); font-size: 13px; }
234
+ input::placeholder { color: var(--muted); opacity: .8; }
235
+ input:focus-visible, select:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
236
+ input[type="checkbox"] { width: 16px; height: 16px; padding: 0; flex-shrink: 0; accent-color: var(--accent); }
237
+ input[type="file"] { padding: 16px 14px; border-style: dashed; }
238
+ input::file-selector-button { border: 0; background: var(--wash); color: var(--accent); border-radius: 7px; padding: 9px 12px; margin-right: 12px; font: inherit; cursor: pointer; }
239
+ label { display: flex; flex-direction: column; gap: 9px; font-size: 12px; color: var(--muted); min-width: 0; margin-bottom: 20px; }
240
+ .checkbox { flex-direction: row; align-items: flex-start; line-height: 1.7; }
241
+ fieldset { border: 1px solid var(--line); border-radius: 12px; padding: 18px; min-width: 0; margin: 18px 0; }
242
+ legend { font-size: 12px; padding: 0 7px; color: var(--muted); }
243
+ .row { display: flex; flex-wrap: wrap; align-items: flex-start; gap: 12px; }
244
+ .row > label { flex: 1 1 160px; }
245
+ .bot-fields { display: flex; flex-direction: column; }
246
+ .bot-fields label:last-child { margin-bottom: 0; }
247
+ form .muted { margin: 12px 0 18px; }
248
+ button:not([class]), button.secondary, a.secondary { display: inline-flex; align-items: center; justify-content: center; gap: 7px; border: 1px solid var(--line); border-radius: 24px; padding: 10px 16px; font-size: 12px; line-height: 1.5; background: var(--surface); color: var(--accent); margin: 4px 4px 4px 0; }
249
+ form > button[type="submit"]:not([class]) { background: var(--accent); color: var(--on-accent); border-color: var(--accent); }
250
+ button:disabled { opacity: .45; cursor: wait; }
251
+ button.danger { font-size: 12px; color: #b06c55; padding: 10px 0; }
252
+ button:hover:enabled { filter: brightness(.98); }
253
+ button:focus-visible, a:focus-visible, summary:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
254
+ h1:focus { outline: none; }
255
+ form { margin-top: 0; }
256
+ .step-content > details { margin-top: 18px; }
257
+ .step-actions { margin-bottom: 12px; }
258
+ .step-actions .muted { margin: 0; }
259
+ .step-count { font-size: 10px; }
260
+ .form-cancel { display: flex; margin: 16px auto 0; }
261
+ .home-more { text-align: center; margin-top: 28px; }
262
+ .home-more > summary { color: var(--muted); font-size: 10px; }
263
+ .home-more[open] { text-align: left; }
264
+ details { min-width: 0; margin-top: 22px; }
265
+ summary { color: var(--muted); font-size: 11px; cursor: pointer; line-height: 1.8; width: fit-content; }
266
+ summary:hover { color: var(--accent); }
267
+ details[open] > summary { margin-bottom: 18px; }
268
+ details p { color: var(--muted); margin: 12px 0; }
269
+ details details { padding-left: 12px; border-left: 1px solid var(--line); }
270
+ pre { white-space: pre-wrap; overflow-wrap: anywhere; word-break: break-word; font: 12px/1.9 ui-monospace, SFMono-Regular, Menlo, "PingFang SC", monospace; color: var(--ink); background: var(--wash); padding: 18px; border-radius: 12px; max-width: 100%; }
271
+ .repository-path { font: 11px/1.8 ui-monospace, SFMono-Regular, Menlo, monospace; color: var(--muted); overflow-wrap: anywhere; word-break: break-word; }
272
+ .profile-repo { text-align: center; margin: 24px 0 14px; }
273
+ .card { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; padding: 16px; margin-top: 12px; border: 1px solid var(--line); border-radius: 12px; min-width: 0; }
274
+ .card > div { min-width: 0; flex: 1; }
275
+ .card > span { font-size: 12px; overflow-wrap: anywhere; }
276
+ .project-card { position: relative; flex-wrap: nowrap; gap: 10px; margin: 0; padding: 21px; background: var(--surface); border-radius: 16px; animation: arrive-row 450ms ease-out calc(var(--order, 0) * 60ms) both; transition: transform 180ms, border-color 180ms; }
277
+ .project-card:hover, .project-card:focus-within { transform: translateY(-2px); border-color: var(--accent); }
278
+ .project-card-info { display: grid; grid-template-columns: 43px minmax(0, 1fr); column-gap: 16px; align-items: center; }
279
+ .project-card-info .project-icon { grid-row: span 2; }
280
+ .project-card-info h3 { margin: 0; font-size: 17px; line-height: 1.5; }
281
+ .project-card-info p { margin-top: 5px; color: var(--muted); font-size: 11px; }
282
+ .project-card > button { font-size: 18px; color: var(--muted); border: 0; margin: 0; padding: 8px; background: none; }
283
+ .project-card > button::after { content: ''; position: absolute; inset: 0; border-radius: 16px; }
284
+ .project-details { margin-top: 30px; }
285
+ .project-details summary { margin-left: auto; margin-right: auto; }
286
+ .robot-card { position: relative; display: grid; grid-template-columns: 40px minmax(0, 1fr); column-gap: 14px; row-gap: 6px; padding: 22px 0; border-bottom: 1px solid var(--line); animation: arrive-row 400ms ease-out calc(var(--order, 0) * 50ms) both; }
287
+ .robot-card::before { content: '⌘'; display: grid; place-items: center; grid-column: 1; grid-row: 1 / 4; height: 40px; color: var(--muted); font-size: 22px; }
288
+ .robot-card.is-mine::before { background: var(--wash); color: var(--accent); border-radius: 12px; }
289
+ .robot-card > * { grid-column: 2; min-width: 0; }
290
+ .robot-card:last-child { border-bottom: 0; }
291
+ .robot-title { display: flex; align-items: center; flex-wrap: wrap; gap: 8px; }
292
+ .robot-title h4 { overflow-wrap: anywhere; }
293
+ .robot-card p { color: var(--muted); font-size: 11px; }
294
+ .robot-connection { display: flex; align-items: center; justify-content: space-between; gap: 12px; margin-top: 5px; }
295
+ .robot-connection > button { font-size: 11px; }
296
+ .badge { font-size: 10px; line-height: 1.5; color: var(--accent); }
297
+ .mine-badge { background: var(--wash); border-radius: 5px; padding: 2px 6px; font-size: 9px; }
298
+ .badge.pending, .warning-text { color: #a47750; }
299
+ .check { display: flex; gap: 16px; align-items: center; justify-content: space-between; padding: 12px 0; border-bottom: 1px solid var(--line); font-size: 12px; }
300
+ .setup-steps { list-style: none; padding: 0; color: var(--muted); font-size: 11px; line-height: 2.4; }
301
+ .setup-steps .done { color: var(--accent); }
302
+ .setup-steps .active { color: var(--ink); }
303
+ .next-step { color: var(--muted); text-align: center; margin: 20px 0; font-size: 12px; }
304
+ #profile #binding > p { color: var(--muted); text-align: center; margin-bottom: 16px; }
305
+ #copy-binding { display: flex; margin: 24px auto 0; }
306
+ #binding > details { margin-top: 24px; }
307
+ #profile-art[data-state="success"] .art-tile { border-radius: 50%; color: var(--on-accent); background: var(--accent); transform: none; animation: success-stamp 550ms cubic-bezier(.2,.9,.3,1.2) both; }
308
+ #profile-art[data-state="success"] .art-tile svg { display: none; }
309
+ #profile-art[data-state="success"] .art-tile::after { content: '✓'; font-size: 29px; }
310
+ #profile-art[data-state="waiting"] .art-tile { animation: settle-tile 650ms ease both; }
311
+ #profile > .step-actions:has(> [hidden] + [hidden]) { display: none; }
312
+ #pending-requests { display: flex; margin: 26px auto; }
313
+ #admin-tools { border-top: 1px solid var(--line); padding-top: 22px; }
314
+ #delivery-panel { background: var(--wash); padding: 18px; border-radius: 12px; margin-top: 24px; }
315
+ #invite-info { display: block; }
316
+ #invite-info p { margin: 0; }
317
+ #invite-info p + p { margin-top: 8px; }
318
+ #project-check-status { margin: 12px 0; }
319
+ #verification .binding-caption { margin: 20px 0; }
320
+ #reset-view > p, #reset-view > ul { color: var(--muted); font-size: 12px; line-height: 1.9; }
321
+ #reset-view form, #existing form { margin-top: 30px; }
322
+ @media (max-width: 600px) {
323
+ main { padding-top: 35px; }
324
+ .row { flex-direction: column; gap: 0; }
325
+ .row > label { width: 100%; flex-basis: auto; }
326
+ .project-card { padding: 19px 16px; }
327
+ .project-card-info { grid-template-columns: 38px minmax(0, 1fr); column-gap: 12px; }
328
+ .project-card-info h3 { font-size: 15px; }
329
+ .project-card-info p { font-size: 10px; }
330
+ .project-actions { gap: 10px; }
331
+ .robot-card { column-gap: 10px; }
332
+ input, select, textarea { font-size: 16px; }
333
+ .robot-connection { flex-wrap: wrap; }
334
+ .card { padding: 14px; }
335
+ .demo-footer > span { font-size: 10px; }
336
+ .theme-picker button { font-size: 11px; padding: 10px 0; }
337
+ }
338
+ @media (max-width: 360px) {
339
+ .project-card { padding: 17px 12px; }
340
+ .project-card-info { column-gap: 10px; grid-template-columns: 34px minmax(0, 1fr); }
341
+ .project-card-info h3 { font-size: 13px; }
342
+ }
@@ -31,6 +31,6 @@ export async function selectProfile({ home = workspaceHome(), selector, cwd = pr
31
31
  }
32
32
  }
33
33
  if (choices.length === 1) return choices[0];
34
- if (!choices.length) throw new Error('未找到已接入项目。请先运行 codex-collab 完成接入。');
34
+ if (!choices.length) throw new Error('未找到已接入项目。请先运行 codex-collab setup 完成接入。');
35
35
  throw new Error(`找到多个接入,请使用 --profile <项目ID> 选择:\n${choices.map((state) => `${state.id} ${state.agent_id} ${state.repo}`).join('\n')}`);
36
36
  }
@@ -0,0 +1,11 @@
1
+ // Keep installation passive: the user chooses when to open the local guide.
2
+ console.log(`
3
+ Codex Collab 已安装。
4
+
5
+ 下一步,运行:
6
+
7
+ codex-collab setup
8
+
9
+ 已有项目时,在项目目录运行可自动带入信息。
10
+ 向导会帮你连接企业微信机器人,或接受同事的邀请。
11
+ `);
@@ -1,9 +1,17 @@
1
- # 旧中心服务实现与边界
1
+ # 架构与范围
2
2
 
3
- 本文描述源码保留的旧 HTTP 模式。当前推荐架构见 [团队接入](onboarding.md)、[Peer 机制](peer.md) 与 [签名团队登记](team-registry.md)。
3
+ 当前只支持企业微信。优先稳定企微的接入、收发、任务领取、交接和真人审核;其他 IM 的接入以后再评估。
4
4
 
5
- 单个中心服务处理群消息、MCP 和 Runner HTTP API;它持有 `agent-collab` Git 独立 worktree,串行追加版本化事件。每位同事在自己的设备配置个人 MCP/Skill,选择性启动 Runner 领取由服务按用户分配的工作;Runner 为每个任务在本地创建独立 Git worktree 与 Codex SDK 会话。代码在 `codex/task-*` 分支,任务事件在 `agent-collab` 分支,两者不相互合并。群消息仅为结构化任务指令和状态摘要,**不共享原始私聊记录**。群内显示的是一个 Bot 代表不同账号的消息,不是真实的多个独立聊天机器人。
5
+ ## 推荐:本机 Peer 与网页向导
6
6
 
7
- 消息路径:飞书/企微消息 -> 允许的群 ID 与平台用户 ID(飞书 open_id / 企微 userid) -> 命令解析 -> 服务权限检查 -> Git 提交 -> Bot 回复。任务路径:分配 -> Runner 领取 -> worktree 编码/提交/可信测试 -> 审查请求 -> 审查 Runner/人工审核 -> 管理员完成。`read_task` 和 `list_tasks` 可让同事桌面 Codex 人工参与;不会唤醒任意已开的桌面会话。
7
+ 每位成员运行本机 Peer,通过自己的企业微信智能机器人接收群消息,将任务交给绑定的已有 Codex 对话。管理员在网页向导中配置项目、分配机器人并批准成员;同事导入加密个人接入包、验证企微身份并绑定对话。项目可以包含多个机器人,每个机器人保留独立身份与权限。
8
8
 
9
- 限制:仅支持单写服务,没有集群式 CAS、持久消息投递队列、续租/心跳、失败后自动恢复或 Git push 冲突重放。默认 localhost;远程接入必须自行部署 HTTPS 和访问限制。飞书或企业微信智能机器人长连接需应用权限、群和成员 ID;企微使用出站 WebSocket,无公网回调。企微尚待新凭据和真实群验证;两种通道都不能只以认证成功代替群收发验证。代理执行陌生仓库代码仍有风险,应在低权限容器隔离。
9
+ 团队目录、任务与交接记录存放在业务仓库的 `agent-collab` 分支,以签名记录校验身份和操作;代码在独立业务分支流转。协作远程与基准分支由向导识别和确认,每个任务固定基准 commit。已有桌面对话依赖显式启用的轮询自动化领取任务,安装 MCP 或 Skill 本身不会唤醒对话。详见 [Peer 机制](peer.md)、[签名团队协议](team-registry.md) 和 [桌面对话轮询](desktop-poll.md)。
10
+
11
+ ## 兼容:旧中心服务
12
+
13
+ 旧模式从源码启动一个 HTTP/MCP 服务,由它维护 `agent-collab` 的独立 Git worktree,串行追加版本化任务事件。每位同事配置个人 MCP/Skill,按需运行 Runner;Runner 创建任务 worktree 和新的 Codex SDK 会话。代码在 `codex/task-*` 分支,任务事件在 `agent-collab` 分支。群消息只提供任务指令和状态摘要,不共享原始私聊记录。此模式由一个 Bot 代表不同账号发送消息,不提供多个独立机器人路由。
14
+
15
+ 消息路径:企微群消息 → 群允许列表与 `wecom_userid` 身份映射 → 命令解析 → 服务权限检查 → Git 提交 → Bot 回复。任务路径:分配 → Runner 领取 → worktree 编码、提交与可信测试 → 审查 → 真人批准 → 管理员完成。只有明确属于当前企微群的任务才能通过群命令访问;历史未知通道数据保留原始来源,不自动转为企微任务。
16
+
17
+ 旧中心服务只支持单实例写入,没有持久消息投递队列、租约、失败自动恢复或 Git push 冲突重放。默认监听 localhost;跨机器需配置 HTTPS 与访问限制。企微智能机器人使用出站 WebSocket,无需公网回调;认证成功与实际群收发需分别验证。旧模式操作见 [中心服务指南](legacy-center.md),不与推荐的 Peer 接入步骤混用。
@@ -2,7 +2,7 @@
2
2
 
3
3
  日常团队接入请使用 [本机网页向导](onboarding.md)。本页保留旧 HTTP 服务操作,npm 包只分发 Peer 与本机向导;旧中心服务须从工具源码启动。
4
4
 
5
- 以下为保留的**旧中心服务模式**操作;不要与上面的 Peer 测试混用机器人连接和命令。Peer 不使用 `localhost:38765`、HTTP 令牌或手工 `协作 分配` / `协作 交接` 命令。
5
+ 以下为保留的**旧中心服务模式**操作;不要与 Peer 混用机器人连接和命令。Peer 不使用 `localhost:38765`、HTTP 令牌或手工 `协作 分配` / `协作 交接` 命令。
6
6
 
7
7
  ## Codex 之间的代码接力
8
8
 
@@ -22,14 +22,14 @@ pnpm install --frozen-lockfile
22
22
  pnpm test
23
23
  ```
24
24
 
25
- 演示目标仓库 `codex-collab-demo` 的 `main` 执行 `sh test.sh`,而任务事件在 `agent-collab`。示例任务 T-001 为故意未完成的编程任务;可用两个不同用户通过 API/MCP 和 Runner 测试。现有 T-001 未指定审核人,建议通过飞书命令创建**新任务**以获得默认管理员审核人。
25
+ 演示目标仓库 `codex-collab-demo` 的 `main` 执行 `sh test.sh`,而任务事件在 `agent-collab`。示例任务 T-001 为故意未完成的编程任务;可用两个不同用户通过 API/MCP 和 Runner 测试。现有 T-001 未指定审核人,建议通过企微群命令创建**新任务**以获得默认管理员审核人。
26
26
 
27
27
  ## 本地启动
28
28
 
29
29
  生成账号文件(不要放进 Git,执行完把终端输出的个人令牌安全地分发给对应用户):
30
30
 
31
31
  ```sh
32
- node scripts/create-accounts.mjs /tmp/collab-accounts.json alice:admin:ou_alice bob:member:ou_bob
32
+ node scripts/create-accounts.mjs /tmp/collab-accounts.json alice:admin:wx_alice bob:member:wx_bob
33
33
  COLLAB_REPO=/path/to/codex-collab-demo \
34
34
  COLLAB_ACCOUNTS_FILE=/tmp/collab-accounts.json \
35
35
  COLLAB_DATA_DIR=/tmp/collab-service \
@@ -37,7 +37,7 @@ COLLAB_REPO_ID=jack506255560/codex-collab-demo \
37
37
  node apps/server/main.mjs
38
38
  ```
39
39
 
40
- 运行成功后 `curl http://127.0.0.1:38765/health`。`ou_alice` 与 `ou_bob` 需要换为飞书用户的**真实** `open_id`。管理员身份为默认审核人;编码负责人不能与审核人为同一人。如需自动领取任务,同事机器运行:
40
+ 运行成功后 `curl http://127.0.0.1:38765/health`。`wx_alice` 与 `wx_bob` 需要换为企微成员的真实 `userid`,可用下方发现脚本获取。账号参数格式为 `id:role:wecom_userid`;暂时仅通过 API 使用时填 `id:role:-`。旧四段账号参数不再接受,已有账号文件与个人令牌可继续使用,补充企微身份时使用 `scripts/bind-wecom-users.mjs`。管理员身份为默认审核人;编码负责人不能与审核人为同一人。如需自动领取任务,同事机器运行:
41
41
 
42
42
  ```sh
43
43
  COLLAB_REPO=/path/to/codex-collab-demo \
@@ -50,57 +50,17 @@ node apps/runner/main.mjs
50
50
 
51
51
  `COLLAB_API` 单机实验可用 `http://127.0.0.1:38765`;不同机器应提供 HTTPS,且每台机器的目标仓库含 `main` 和 `agent-collab` 分支。若跨机器分发代码分支,需要在服务和 Runner 均设置 `COLLAB_PUSH=1`,保证 origin 可访问且个人 Git 凭据已配置。服务向 `agent-collab` 推送账本,Runner 向 `codex/task-*` 推送代码;**没有凭据会失败**。不能直接把 localhost 地址给其他同事。
52
52
 
53
- ## 飞书接入
53
+ ## 企业微信群接入
54
54
 
55
- 1. 飞书开放平台创建企业自建应用,启用机器人、申请“以应用身份发送消息”和接收群消息所需权限;启用 `im.message.receive_v1` 事件,选择**长连接**接收并发布/授权应用(具体权限以飞书控制台当前要求为准)。
56
- 2. 将 Bot 加到群中,先在本机设置 `FEISHU_APP_ID`、`FEISHU_APP_SECRET` 并运行 `node scripts/discover-feishu.mjs`;在目标群发一条普通消息,终端只打印 `chat_id` 和 `sender_open_id`(不会保存正文),确认所有同事的 open_id 后停止该脚本,再填入账号文件与 `FEISHU_CHAT_IDS` 允许列表。**不要**写死或提交 App Secret。
57
- 3. 启动中心服务时追加:`FEISHU_APP_ID=... FEISHU_APP_SECRET=... FEISHU_CHAT_IDS=oc_...`。看到 WebSocket 订阅日志后,在允许的群由已映射成员发:`协作 创建 写一个功能 | 验收一;验收二`,管理员 `协作 分配 T-... bob`,所有人 `协作 状态 T-...`。Runner 提交审核请求后审核人 `协作 审核 T-... 通过` 或 `协作 审核 T-... 退回`,最后管理员 `协作 完成 T-...`。
58
- 4. 检查群回复、服务日志、目标仓库 `agent-collab` 事件与本机代码分支。未配置飞书凭据时可以跑本地模拟 E2E;模拟通过**不等于**真实群接通。
55
+ 1. 在企业微信创建支持 API 长连接的智能机器人,取得 Bot ID 和 Secret,并加入协作群。它通过官方 `@wecom/aibot-node-sdk` 建立出站 WebSocket,无需公网回调。一个 Bot 对应这一个中心服务,由私有账号文件区分成员。
56
+ 2. 在本机交互终端设置 `WECOM_BOT_ID`、`WECOM_BOT_SECRET` 后,运行 `node scripts/discover-wecom.mjs`。等待认证成功,再在目标群 @机器人发送文本。脚本只输出 `chatid` 和 `userid`,不输出正文。记录群和成员 ID 后,按 `Ctrl-C` 停止发现脚本,再启动服务;同一个机器人只保留一个连接。
57
+ 3. 新账号直接按上方三段格式生成;已有账号可运行 `node scripts/bind-wecom-users.mjs <旧账号文件> <新账号文件> 'alice:<真实userid>' 'bob:<真实userid>'`,再将 `COLLAB_ACCOUNTS_FILE` 指向新文件。此脚本保留个人令牌哈希,不改原文件。不同账号不能绑定相同 `userid`。
58
+ 4. 启动中心服务时同时设置 `WECOM_BOT_ID`、`WECOM_BOT_SECRET` 和 `WECOM_CHAT_IDS`,多个群 ID 用逗号分隔。凭据保存在本机私有环境,群 ID 和成员 ID 不提交到 Git。未配置机器人时只启用 HTTP/MCP API。
59
+ 5. 在允许的群由已映射成员依次验证:`协作 创建 写一个功能 | 验收一;验收二`、管理员 `协作 分配 T-... bob`、`协作 状态 T-...`。Bob 的 Runner 领取后,提交代码与测试证据并请求审查;指定审核人核对结果后执行 `协作 审核 T-... 通过` 或 `协作 审核 T-... 退回`,管理员最终执行 `协作 完成 T-...`。批准和完成均需真人明确操作。
59
60
 
60
- ## 本机接企业微信群(已有隔离 demo 和两个 Runner 时)
61
+ 认证成功、群消息到达、群回复和主动任务通知需分别验证。排查无回复时可临时设置 `COLLAB_WECOM_DIAGNOSTICS=1` 并重启服务;诊断不输出正文、凭据或群/成员 ID。Runner 需单独启动,HTTP 服务不会代为启动它。
61
62
 
62
- **先在企业微信管理端创建/配置支持 API 长连接的智能机器人**,获取 Bot ID 和**新** Secret,加入测试群。此前曾在聊天里暴露的 Secret 已不安全:必须先重置,不要再次发送到聊天或提交 Git。此处用的是「智能机器人 API 模式」,不是只有 webhook URL 的群机器人;连接通过官方 `@wecom/aibot-node-sdk` WebSocket 出站发起,不需要公网地址。确认组织管理员允许此类型机器人、目标群确实能收到其群消息。一个 Bot 足够;它通过账号映射和本地两个 Runner 分配身份,不对应两个桌面 Codex 会话。群消息能否到达以真机发现为准,尝试在群内 @ 机器人发送文本。
63
-
64
- 当前单机测试目录可以这样找(不要打印里面的令牌或环境文件):
65
-
66
- ```sh
67
- cd "$HOME/codex-collab"
68
- # 确保 Node.js >= 20 已安装并且 node 位于 PATH。
69
- root="$(cat "$HOME/.codex-collab-local-test/current")"
70
- # 仅在你的本机交互终端输入;不要把实际值放在命令行参数或聊天中。
71
- printf 'Bot ID: '; IFS= read -r WECOM_BOT_ID
72
- printf '新 Bot Secret(不回显): '; IFS= read -rs WECOM_BOT_SECRET; echo
73
- export WECOM_BOT_ID WECOM_BOT_SECRET
74
- node scripts/discover-wecom.mjs
75
- ```
76
-
77
- 等待输出 `WeCom authenticated`,在目标群里向机器人发送文本,例如 `@机器人 协作 状态 T-NONE`;发现脚本仅输出 `{"chatid":"...","userid":"..."}`,**不会输出正文**。这一步如果只有认证而没有群消息,不代表群已接通:检查群是否已加入机器人、消息触发方式和企业管理员配置。在发现脚本按 `Ctrl-C` 关闭连接,再继续下面步骤;**同一个机器人不要让发现脚本和服务同时建立连接**。至少记下一个真实群 `chatid` 及你(管理员 alice)的 `userid`,若同事要在群里发命令,再收集其 `userid`。不要猜 ID、不要贴到 Git。以下命令的引号和交互输入要保留:
78
-
79
- ```sh
80
- printf '刚发现的群 chatid: '; IFS= read -r WECOM_CHAT_IDS
81
- printf '你自己的 userid(alice): '; IFS= read -r ALICE_WECOM_USERID
82
- export WECOM_CHAT_IDS
83
- node scripts/bind-wecom-users.mjs "$root/accounts.json" "$root/accounts.wecom.json" "alice:$ALICE_WECOM_USERID"
84
- # 可选:另一位真人需在群里操作时,用他的 userid 重建私有文件;不要把两人的 userid 填成同一个。
85
- # node scripts/bind-wecom-users.mjs "$root/accounts.json" "$root/accounts.team.json" "alice:$ALICE_WECOM_USERID" 'bob:<同事的真实userid>'
86
- # 新文件只保留原有的个人 token 哈希,原有 Runner 令牌不会变化。
87
- . "$root/private.env"
88
- export COLLAB_ACCOUNTS_FILE="$root/accounts.wecom.json"
89
- # 仅停原中心服务,保持两个 Runner;先确认旧 PID 确实是本工具的服务。
90
- old="$(cat "$root/server.pid")"
91
- ps -p "$old" -o command=
92
- # 仅在确认该进程属于当前仓库的 apps/server/main.mjs 后,才手动执行:kill "$old"
93
- node apps/server/main.mjs
94
- ```
95
-
96
- 上面最后一条**前台运行**,该终端不要退出;另开终端 `curl http://127.0.0.1:38765/health` 检查服务。若提示端口占用,先核对旧服务 PID,勿盲目杀其他进程。若群中收到真实回复才算接通。群里的任务示例:
97
-
98
- 1. `协作 创建 给 greet.sh 增加 --upper 行为 | sh test.sh 通过;sh greet.sh --upper 输出 HELLO, WORLD;保留原有默认输出`,记下新任务 `T-...`;不要重复使用历史任务。
99
- 2. `协作 分配 T-... bob`;本机 Bob Runner 自动领取并在隔离副本创建 `codex/task-*` 代码分支。Alice Runner 可读取审查任务并写私有审查记录。
100
- 3. `协作 状态 T-...`;人工核对 `git -C "$root/demo" branch --list 'codex/task-*'`、`sh test.sh`(需要在**任务分支**的 worktree 执行;`main` 故意未完成,不能直接把它的失败当任务失败)和 `$root/server-data` 的 Git 账本;不能把 Runner 记录当人工批准。
101
- 4. 确认代码和测试证据后,由 **alice 真人**发 `协作 审核 T-... 通过`,再发 `协作 完成 T-...`;这两个动作不会由 Runner 自动执行。失败就 `协作 审核 T-... 退回`。
102
-
103
- **注意**:发现、认证、模拟 E2E、真实群消息送达、群回复、主动任务通知是不同的成功条件;逐项核实。这里使用 `$root/demo` 隔离副本,不修改或推送原始 demo 仓库。`COLLAB_PUSH` 单机保持默认关闭;源仓库与真实企业账号信息勿放入 Git。若之前本机 Runner 不在运行,查看 `ps` 与 `apps/runner/README.md`;不要以为启动 HTTP 服务就会自动启动 Runner。
63
+ 当前只支持企微;新群任务明确写入 `channel: "wecom"`。历史任务的原始来源保留,不会被自动改写成企微来源;缺少通道或属于其他通道的任务不能在企微群查询,也不会向企微群发送通知。API 任务可继续通过已授权 API/MCP 操作。
104
64
 
105
65
  ## 同事接入 MCP 和 Skill
106
66
 
@@ -126,3 +126,12 @@ Skill 校验通过。`npm pack --dry-run` 确认发布包包含 `guided.mjs`、`
126
126
  持续动画仅有两处背景光晕位移与就绪状态透明度变化;在动画稳定后的 1.8 秒 Chrome Performance 采样中,新增 LayoutCount、RecalcStyleCount 和 ScriptDuration 均为 0。此记录反映本机隔离示例,不代表所有设备上的帧率。一次性入场动画完成后不保留最终变换。系统减少动态效果设置能关闭全部动画;页面隐藏信号能暂停动画,后台项目轮询不发出同步请求。
127
127
 
128
128
  npm tarball 在独立目录安装后,命令入口、带会话鉴权的 API、新项目读取路由和静态页面资源检查通过。包包含 77 个文件,含新增项目聚合模块,不包含测试目录、本机凭据、运行日志或截图。此轮验证未连接真实企业微信群、修改个人业务 clone 或建立 Codex 自动化;任务协议与既有操作授权保持原有行为。
129
+
130
+
131
+ ## 2026-10-24 · 0.9.0 轻引导与安装提示
132
+
133
+ 正式向导采用单列居中的分步流程:首页按项目展示,项目中统一列出机器人并标记“我的”;接入项目、接受邀请和添加本人机器人均按步骤收集必要信息。远程、分支、验证命令、团队管理、诊断和重置按需展开。上一步保留输入;项目存在歧义或缺少验证命令时要求确认;完成页只依据实际对话绑定和轮询记录更新,复制指令不会视为接入完成。配色、原生与 CSS 动画支持减少动态效果偏好和后台暂停。
134
+
135
+ 完整自动测试通过 215 项,0 失败。浏览器使用真实页面资源和隔离示例服务,检查管理员接入、成员邀请、添加本人机器人、返回保留输入、真实状态驱动的群验证和绑定阶段、归属标记、管理入口,以及切换项目时清理旧状态。320、390、768、1024、1440 像素宽度、三种配色、减少动态效果和动画结束状态检查通过,未出现脚本、控制台或资源错误。此轮未连接真实企业微信群或建立真实 Codex 自动化,不构成跨机器联合验收。
136
+
137
+ npm 包新增被动安装提示,引导执行 `codex-collab setup`;不会在安装期间自动启动服务或打开浏览器。npm 默认可能隐藏生命周期脚本输出,因此文档推荐使用 `npm install --global --foreground-scripts xuym-codex-collab` 并明确列出 setup 命令。安装脚本和全部向导资源已打包;独立临时目录实际安装及 CLI 入口检查通过。设计演示源码保留在 `design-demos/onboarding/`,演示和本机截图不进入 npm 包。