Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 18 additions & 11 deletions SHA256SUMS
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,11 @@ ecd8294e24a1cd55cc1aa0b3c5d6cde68c956524cfb1d7707766b4f6287b5e3e activity/index
2c22d3a5e0aff57971932e24cbdf4dc93c12f589b060203cc20417fd97a75142 activity/legal/legal.css
6c8b74d4d57bff38a393ab038418c8f410627dc66721bc416905289110f151ac activity/legal/privacy.html
297c926eb462285e52e196af2d23f2ac70cb280324bfd30aeff74836e02f159c activity/legal/terms.html
83aaa4a638d927b803c08e84b30b1b09e4d152e325caf57583acb77d2e59ca35 activity/src/channel-selectors.ts
ac5a46a57d2c4ba90ed861c840b7240c9367359bbb21c8167890a7a61211f783 activity/src/connection.ts
2e6808727e3230b32d41b1c37a3c50c1029d8a48edda6d43eddd20ad4cebeed1 activity/src/main.ts
4ebc81c7b8afd960ee6249ee60086606082e88240c1d7fbc05c30e125b75d307 activity/src/onboarding.ts
66988416b7ab216ad9d3947ed528bfe9f2e45f74943971d506a686ff0b044508 activity/style.css
c867e30a7ff9a3973c1da711e3f490d36f00486d83b90031cc8eeff9c7e52af3 activity/src/main.ts
70bb37e2c8ae4922d743719423c39724249d63cdb36535e724e37abaf2107339 activity/src/onboarding.ts
e27c8e4fcb06b80be53356b8c22494867e43dfe0816cd8ae008b2d01814a9b9a activity/style.css
3fb468ea85cd082f252d85b34bb3da8b62a10ae4aa984b48ef93f0ecacc7017f data/scams/README.md
2b1733d3ba70cd80dc5e91720f0deacf0fced2145e9af5d0e5f4029c50001694 data/scams/SHA256SUMS
cbd96b7facc13c15deea51a8db245044bfba2b234d2573aa3cb638247ff0b82a data/scams/images/scam_03_cbd96b7f.jpg
Expand Down Expand Up @@ -70,8 +71,8 @@ aec6cfde3d69458895924c9bf66e9a0f5831a8f4b18c31dbfef8a35899001531 data/scams/ima
38e139c05672e5fdf2db5eebfb1d1fc28ead5f014bc77ac65d005dda9f9a2429 db/mysql/004_packs.sql
10c485e37724a59c7fab34713b065a9dd271788b82a2a1eeb7242d001f8e6c79 docker-compose.yml
c5fd8324e1e65527f7208a0fc0669ceab4cd4aab9d1dae517e46bbe754f3c101 docs/ACCEPTANCE.md
ce3922770e54865dab09b7fe5d3ac44018015595193e84f35c3018a14c1503cf docs/AGENT_ONBOARDING.md
e77b36946c2cd3e87400a8ef30821a9e620775034537e5a61b1d00fa408d0f78 docs/API.md
86a574d815a17151c47e25121bb3934d619ffcf7c256b3b72bb6c92aaf0fa57e docs/AGENT_ONBOARDING.md
e87992811040458e7261ef934b26961334aa1ca1061abe26ce05b9d4b6af161e docs/API.md
24861f458f5bba54f223f5903aefe9300793c154cd25958b7ac4f46072a8647a docs/CONTENT_ANALYSIS.md
9c81d1916b565043cc438787fc43b2e5719ff7aac78846f5d32ec7035fdb9d7d docs/COSTS.md
9ade67158bf9c08e1bde20d12401658a23c08df186871f869f32fa476dbd800f docs/DEPENDENCIES.md
Expand Down Expand Up @@ -107,6 +108,9 @@ cbaaa4a0c8764151326e307e68769959b0b838e83870dca37bd221bd58a91593 docs/assets/pa
9f51edae070e5e17499d400697eedbef32b3c649a2ee16d33aaba077302daf3e evidence/browser-smoke.json
9f51edae070e5e17499d400697eedbef32b3c649a2ee16d33aaba077302daf3e evidence/browser-smoke.stdout.txt
cd5753b7b637f976f1d2934f02a951331fba6f0cbae493c685a4c31c5e784005 evidence/build-attempt.txt
3ef9def3dc5e3dd0f903908ee587ee2ab2bb46ac44b6c7c8aa7a3d2969883cf5 evidence/channel-picker-browser.json
18095ab84e72c1593724e18e783ef64b1b021a3e245124230e30edd1492a9da7 evidence/channel-picker-dark-browser.json
d45811f4a4adc48ba88064266670ca0e0401b9e0ca3e831e101d7f217283d6dd evidence/channel-picker-validation.md
4404379e485bc76e1ac574effc6501012a4bb688830ed6bc881e302c84624957 evidence/claude-handoff.txt
588479fe70623fde7e67c3b5672e07cca655d8e9cd1b444f31d80db1144a4e07 evidence/claude-launch.json
8e6ac2c64a73048fbc317fd6e1d6d41f297404c4b7993bafb96b134ec3eaf0fe evidence/claude-live-status.json
Expand Down Expand Up @@ -347,9 +351,10 @@ aca709e061483406ad4d148f406a228d7f0903d3d9a57b7c9a8e809539b791be package-lock.j
8fe23e9220e323d9645efa4ec5a9fdb0fa3af54aad8b12b236d14b336f66128a package.json
75a51a1edf0401ec598fc10d3de13092c89798b2fb98e9955bd82978e7591e99 planning/typesafe_theme/PROMPT.md
6072f6baa634eabd00a3c94d31fe4eb09b6536bbacf2c1b09a3defe917b4b249 scripts/benchmark_costs_test.py
46024b769c5f7d0438d9b94734abe5cb0892715182d7df2bdf7ed1f138ca1c4e scripts/browser-smoke.py
df6d3e89cc8d5fd122597c9d753e862e8625733a92d764c8035d8fbfcb6b3311 scripts/browser-smoke.py
b04d6d317aa99ec83e08e5fe6bc799316b89e4990624c5c779af7eb53999792c scripts/build-starter-packs.mjs
14ff797db89891ca6e55eb27cbd39002ef6541f626fa649ef8bdcf134712094c scripts/bundle-sdk.mjs
e569cb02a830b91b559caa2eb5c12baf7f5090359fb7dd25a17f231dc7cec04d scripts/channel-picker-browser.mjs
b959732b8d60eade13e147a7217fbdd043e6663ba91d8c3a8d578d2c99387d57 scripts/format-source.mjs
2b02528f27795107fe6b25d0d6c3c481ca85dfa8bed7680794aa285dae87acff scripts/generate-content-fixtures.mjs
a86918d94a72b36c6b2fec7699945b9c82937ec1bcfcb92f8e00410af1b04a25 scripts/generate-fixtures.py
Expand All @@ -360,15 +365,15 @@ c29b2921019f406d52ea97f99b24f5fb1b3d7d188bd5be54bf40a2b3ca60de58 scripts/kaggle
d3454c1ef2f5bd1b871358485104dfb5b849c53f13d8b9b892cc0e2cdfbe2570 scripts/migration-receipt.mjs
fbe41f990d155b158571ba0b8db5c5138f5cbbeb20ce6b84059aecb7d9f9b00a scripts/migration-receipt.test.mjs
b2d7f56ef5420637227298102779b2b2e07d3c56b7dbbdc32ff1bb1c99107acb scripts/onboarding-browser-server.mjs
5699a82961b50dfbb0eabc02833b378a7447160c753af8e306aa749bca212d1d scripts/onboarding-browser.py
74cd5220191c15544a56687f63e8289fa2075f45b39eee02239a3f0a06d056c0 scripts/onboarding-browser.py
2c2432b67c1739d50bd339ba9d6504ace9a9f2bf20afa8deef67daef7110ed50 scripts/onboarding-live.mjs
a9ba710e3953aebf3557647bda6447a807dca2e023f3dd588955ae6faf65edea scripts/pack-browser-workflow.js
071b1afae64f798864ce9cefcb95d4642a2b17e97d3f06efb1df235653a9c32a scripts/pack-browser.py
69acf3b325a0e822ea4b707008730c09c12b579337253b5d2186459f0ac64eba scripts/pack-ui-server.mjs
cd6086ef58cb792cbba53b22720fb262325cfc3f7ef1991ad3084a230416cba0 scripts/prepare-kaggle-benchmark.py
a0ef941ecb2ffab8069cb7bbd5a65d986ac73a156150c88bfbeb6a93d48ad121 scripts/preview-cost-data.mjs
137a80462534c728edbcdb1a3a99d58b12085e73f168e6fc84b642ed80ba38dc scripts/preview-data.mjs
ad328f143a469015bef8257df90cfe9a43b2bb9d20ed4d2d86ecaeb94c89f6bd scripts/preview.mjs
a4c40fd2993d319c8244cdd1b3c6cf504924eea574da23abfa51cf6accbd760d scripts/preview.mjs
2c6a2e079315c17bd9440a6e8459f681e7e0f7096d47c847408dae6fb129d802 scripts/release-guard.mjs
75ed3eb1a7d030bdcda453db532d59509ba4ab4bf2506762a2f018f4b89d1717 scripts/release-guard.test.mjs
c950b5c85188d4fc4a40be4e097e4e60dcd5bcd675059b02ce63108532f36704 scripts/release-source.mjs
Expand Down Expand Up @@ -397,20 +402,20 @@ a44e797125685b375a99f8ea8311972906255b05cdc4df91ea9beb0c8860e185 scripts/verify
b5e028d6a57cf4c6458f70c8411d2b95f561b48b212bf88cb8d04e3ea3efeeee server/content-evaluate-cli.ts
c7678b37fef2837eece5de6da59b919a9d00bbec87c44c677930b5ad717ebd04 server/content.ts
c3a5c6c6c01a10e2682f827d04f43fcb72f50fb8f3eb70690f28d78e130fd7b0 server/database.ts
bc116f5d23abe9b47bf28b328f360c5176b50eb4e8907783ba2f841f531db0cc server/discord.ts
a694df578b067610c3fecee5fa795079a171a0f6bf11cfc732449e521bc49352 server/discord.ts
ba6fb59bda1bf219d1e09d787a52437bf4a0ae6bfabfbda2bcfb37bced886adc server/durable.ts
89e116491a077a347c18b0b0c6a2801f867f0005c224ab5ed6e2dd3d783c047a server/evaluate-cli.ts
6e00b4f2c76c2b68165105b9ca9a00dbc74183043d15ba4d5ffb82967b84130f server/gateway.ts
f72b36e636d98f35f21d9e185aaf5ca7376ef20de2769e5c4a8a107022bcf832 server/historical.ts
af65a397602bd3b3907c59a542e44e8047010766016471696e926b839e29b48b server/http.ts
d1caddc1ebc77442d5be4445edad8bd3e182211852052c95be8781a8db8e424a server/http.ts
98a99e3407ace650bc8b1c9140d31548c378e0b2e1069e43dbed6325f5acf26b server/images.ts
6af6aa0e5917a1ec062d2076c6ae60a4cb94af546266e9fd4b746502a7a743a3 server/jev.ts
b556bb54b61153d824e83a5a931c7031974736e065dc63633e259090c3e7eb0d server/leadership.ts
b378f81be6a5ec3d533c525ed6e99669a848484639bcbff468912b8284d3c27c server/main.ts
fafb6781d39a74e7c1cf3e1be1daf28ee71141cf93cdbd28d37a1327e2574b3c server/migrate.ts
37c04181dfa9f14b7dd6da07376b277831d6665c5e8500814d007255c7aa1968 server/mysql-pool.ts
3846c2120719c93d6c9d97c74f8760ee20540f95762c2e937add6df137fea6dd server/mysql.ts
cb4d6d5b69db9f50bec2740550b3834ff0008241d8e36086423995e3d7ba5929 server/onboarding.ts
90901119d5ca1f8de03d906ba4bafebbfc0eddb331be3b9b416e6efa9e91bd71 server/onboarding.ts
9ccf13b87d8bdbca1557edc7f8e3f7e6f104598a75c9c74f9801cb9224ac8dfd server/pack-starters.ts
65592be0bb260c0f821237187c78c52ed0c62f7d51e7b80094c0be38ffa1f542 server/packs.ts
ee71b7b16b22b417ea8bf27c51aa7342e725070e4186f72fc80bf5d661121880 server/policy.ts
Expand All @@ -426,6 +431,7 @@ b3a578846c1e5d503d63ac65fd098c78e42f984dda22bd086f3afdb18b875ca2 server/text-st
2a9e121432d479f8901b11594f0b48e62d9bd45c6fd3b58d797017d3388d8c0d server/usage-sql.ts
4a4258f350c742104aa4c33f9d889774e66466cc6b9d3ce017e3f7e1a9067d71 server/worker.ts
dec2ef8a73677cdfccba0ba8bb59a8d578e921b314398cafda3c23765da5da59 shared/analytics.ts
5b642b8f6e2a23b300438cb1a6375cd8f67865cfb29ff059c99bc023bf9a3363 shared/channels.ts
73a43aba903b47d573c7ebd7ef966dcfe6d16da8f2420d3b894c72ba57b0a906 shared/content-metrics.ts
969336e4689745de39e5dd84dc16868bbd52181fe262ece8ee5aee215d767fe8 shared/content.ts
cc655a15e777c5bb85cc16a93a2fc1cfb5008e6db654441ced48604bd3059df0 shared/domain.ts
Expand All @@ -442,6 +448,7 @@ d1611476abf0bc8ab0e1d4ccfea0abaa232183aa144390d56a8cf00f7468d984 starters/custo
20868d9d3d3760a4f19cc5aa97ef6496dd3e076507d9eb1b333a8f5ea9691d1e starters/reviewed-scam-references.typecheck.json
28dda44df880208b1aaf2fe7454563d866fc83ac8096b0f5e88cd7c3ef2261c8 tests/activity-connection.test.ts
2257548bf1aa1de3113925dbdbd367db1211f5692ea6e0e69dae9830ef6ca611 tests/analytics.test.ts
3f636811cb93ccb0e24cd278e442b3145ed2fe3e258591151600ea05093ae8f5 tests/channels.test.ts
977ac57a09795d86d5d5211ca91fa42db9e4f2b63442b0daadfb16025d42ef1c tests/compose.env
f9c22e2e2b1b12d1463e433966978b3cffb6f57e6903aae9d97d2d47a13eaed7 tests/compose.validation.yml
67cd5970cfecef6cd92fb9b0be95c00bb106bcac1cc4a0f8f368aa95905ef4a8 tests/content.test.ts
Expand Down
80 changes: 80 additions & 0 deletions activity/src/channel-selectors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { orderedChannelGroups, type ChannelMetadata } from '../../shared/channels.js';

export interface RoleMetadata { id: string; name: string; position?: number }

function element<K extends keyof HTMLElementTagNameMap>(tag: K, text = '', className = '') {
const node = document.createElement(tag);
node.textContent = text;
node.className = className;
return node;
}

function option(value: string, name: string) {
const node = element('option', name);
node.value = value;
return node;
}

function channelOptions(channels: readonly ChannelMetadata[]) {
const select = element('select');
for (const group of orderedChannelGroups(channels)) {
const section = element('optgroup');
section.label = group.name;
for (const channel of group.channels) section.append(option(channel.id, channel.name || 'Unnamed channel'));
select.append(section);
}
return select;
}

function multipleField(title: string, input: HTMLSelectElement, selected: readonly string[], onChange?: (values: string[]) => void) {
const node = element('label', '', 'field channel-picker');
node.append(element('span', title, 'field-label'), input);
input.multiple = true;
input.size = 8;
for (const item of input.options) item.selected = selected.includes(item.value);
const values = () => [...input.selectedOptions].filter(item => !item.disabled).map(item => item.value);
input.addEventListener('change', () => onChange?.(values()));
return { node, input, values };
}

/** Category headings are optgroups; only text and announcement channels are selectable. */
export function channelMultiSelect(title: string, channels: readonly ChannelMetadata[], selected: readonly string[] = [], onChange?: (values: string[]) => void) {
const input = channelOptions(channels);
const available = new Set([...input.options].map(item => item.value));
const unavailable = selected.filter(id => !available.has(id));
// A refresh must not silently erase a saved selection if Discord no longer returns it.
if (unavailable.length) {
const section = element('optgroup');
section.label = 'Unavailable channels';
for (const id of unavailable) section.append(option(id, `Unavailable channel (${id})`));
input.append(section);
}
if (!input.options.length) {
const empty = option('', 'No text or announcement channels are available.');
empty.disabled = true;
input.append(empty);
input.disabled = true;
}
return multipleField(title, input, selected, onChange);
}

export function roleMultiSelect(title: string, roles: readonly RoleMetadata[], selected: readonly string[] = [], onChange?: (values: string[]) => void) {
const input = element('select');
for (const role of [...roles].sort((a, b) => (b.position ?? 0) - (a.position ?? 0))) input.append(option(role.id, role.name));
for (const id of selected.filter(id => !roles.some(role => role.id === id))) input.append(option(id, `Unavailable role (${id})`));
if (!input.options.length) {
const empty = option('', 'No roles are available.');
empty.disabled = true;
input.append(empty);
input.disabled = true;
}
return multipleField(title, input, selected, onChange);
}

export function channelSelect(channels: readonly ChannelMetadata[], selected = '', emptyLabel = 'No log channel') {
const select = channelOptions(channels);
select.prepend(option('', emptyLabel));
if (selected && ![...select.options].some(item => item.value === selected)) select.append(option(selected, `Unavailable channel (${selected})`));
select.value = selected;
return select;
}
Loading
Loading