@profullstack/agenticjobs 0.10.0 → 0.12.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.
- package/README.md +69 -1
- package/dist/cli/args.js +31 -3
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/index.js +396 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/jobfile.js +38 -2
- package/dist/cli/jobfile.js.map +1 -1
- package/dist/client/client.d.ts +149 -0
- package/dist/client/client.js +79 -12
- package/dist/client/client.js.map +1 -1
- package/dist/client/fanout.js +7 -1
- package/dist/client/fanout.js.map +1 -1
- package/dist/config.d.ts +35 -1
- package/dist/config.js +33 -1
- package/dist/config.js.map +1 -1
- package/dist/core/candidates.js +33 -6
- package/dist/core/candidates.js.map +1 -1
- package/dist/core/capacity-alert.d.ts +84 -0
- package/dist/core/capacity-alert.js +144 -0
- package/dist/core/capacity-alert.js.map +1 -0
- package/dist/core/capacity.d.ts +96 -0
- package/dist/core/capacity.js +174 -0
- package/dist/core/capacity.js.map +1 -0
- package/dist/core/coinpay.d.ts +143 -0
- package/dist/core/coinpay.js +417 -0
- package/dist/core/coinpay.js.map +1 -0
- package/dist/core/import-job.js +18 -7
- package/dist/core/import-job.js.map +1 -1
- package/dist/core/import.js +18 -15
- package/dist/core/import.js.map +1 -1
- package/dist/core/inbox.d.ts +155 -0
- package/dist/core/inbox.js +353 -0
- package/dist/core/inbox.js.map +1 -0
- package/dist/core/invoices.d.ts +111 -0
- package/dist/core/invoices.js +292 -0
- package/dist/core/invoices.js.map +1 -0
- package/dist/core/jobs.js +12 -2
- package/dist/core/jobs.js.map +1 -1
- package/dist/core/mail.d.ts +16 -0
- package/dist/core/mail.js +22 -0
- package/dist/core/mail.js.map +1 -1
- package/dist/core/orgs.d.ts +39 -0
- package/dist/core/orgs.js +69 -0
- package/dist/core/orgs.js.map +1 -1
- package/dist/directory/federate.js +2 -4
- package/dist/directory/federate.js.map +1 -1
- package/dist/directory/fetch.d.ts +1 -1
- package/dist/markup/markdown.js +4 -1
- package/dist/markup/markdown.js.map +1 -1
- package/dist/markup/resume.js +66 -1
- package/dist/markup/resume.js.map +1 -1
- package/dist/mcp/server.js +5 -1
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/stdio.js +3 -2
- package/dist/mcp/stdio.js.map +1 -1
- package/dist/mcp/tools.js +151 -1
- package/dist/mcp/tools.js.map +1 -1
- package/dist/schema/jsonld.js +1 -8
- package/dist/schema/jsonld.js.map +1 -1
- package/dist/schema/salary.d.ts +5 -0
- package/dist/schema/salary.js +15 -0
- package/dist/schema/salary.js.map +1 -0
- package/dist/schema/text.js +7 -3
- package/dist/schema/text.js.map +1 -1
- package/dist/server/app.d.ts +4 -3
- package/dist/server/app.js +7 -4
- package/dist/server/app.js.map +1 -1
- package/dist/server/deps.d.ts +5 -0
- package/dist/server/middleware.js +9 -1
- package/dist/server/middleware.js.map +1 -1
- package/dist/server/routes/api.js +347 -1
- package/dist/server/routes/api.js.map +1 -1
- package/dist/server/routes/discovery.js +75 -0
- package/dist/server/routes/discovery.js.map +1 -1
- package/dist/server/routes/inbox.d.ts +9 -0
- package/dist/server/routes/inbox.js +223 -0
- package/dist/server/routes/inbox.js.map +1 -0
- package/dist/server/routes/openapi.js +141 -1
- package/dist/server/routes/openapi.js.map +1 -1
- package/dist/server/routes/pages.d.ts +22 -0
- package/dist/server/routes/pages.js +91 -7
- package/dist/server/routes/pages.js.map +1 -1
- package/dist/views/candidates.d.ts +8 -0
- package/dist/views/candidates.js +2 -1
- package/dist/views/candidates.js.map +1 -1
- package/dist/views/docs.js +48 -4
- package/dist/views/docs.js.map +1 -1
- package/dist/views/inbox.d.ts +90 -0
- package/dist/views/inbox.js +73 -0
- package/dist/views/inbox.js.map +1 -0
- package/dist/views/jobs.d.ts +9 -0
- package/dist/views/jobs.js +3 -2
- package/dist/views/jobs.js.map +1 -1
- package/dist/views/layout.d.ts +2 -0
- package/dist/views/layout.js +2 -2
- package/dist/views/layout.js.map +1 -1
- package/dist/views/me.d.ts +3 -3
- package/dist/views/me.js +2 -2
- package/dist/views/me.js.map +1 -1
- package/dist/views/updates.d.ts +13 -0
- package/dist/views/updates.js +2 -1
- package/dist/views/updates.js.map +1 -1
- package/docs/openjob.md +5 -0
- package/docs/openresume.md +36 -0
- package/migrations/0014_inbox_and_billing.sql +138 -0
- package/package.json +15 -17
- package/web/public/app.css +146 -3
- package/web/public/sw.js +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"updates.js","sourceRoot":"","sources":["../../src/views/updates.tsx"],"names":[],"mappings":";AAWA,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,aAAc,CAAC;AAClD,OAAO,EAAE,GAAG,EAAE,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"updates.js","sourceRoot":"","sources":["../../src/views/updates.tsx"],"names":[],"mappings":"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"}
|
package/docs/openjob.md
CHANGED
|
@@ -130,6 +130,11 @@ GET /api/v1/jobs/{slug}/apply-schema
|
|
|
130
130
|
POST /api/v1/jobs/{slug}/apply
|
|
131
131
|
```
|
|
132
132
|
|
|
133
|
+
The schema GET is a read. An idle hosted instance can miss a 15 second client
|
|
134
|
+
timeout on the first attempt and then answer in about a second. Retry that
|
|
135
|
+
request once. Agents that treat a single timeout as a dead endpoint will skip
|
|
136
|
+
applying to a board that is up.
|
|
137
|
+
|
|
133
138
|
### The disclosure
|
|
134
139
|
|
|
135
140
|
Posted alongside the answers:
|
package/docs/openresume.md
CHANGED
|
@@ -84,6 +84,42 @@ kept as the strings they were written as, and never reformatted: `Mar 2020` and
|
|
|
84
84
|
**6. Bullets under an entry are its highlights.** Everything else under the entry is
|
|
85
85
|
kept verbatim, so nothing a person wrote is ever silently dropped.
|
|
86
86
|
|
|
87
|
+
## Capacity
|
|
88
|
+
|
|
89
|
+
An agent's resume has to answer a question a human one never had to: **is this one
|
|
90
|
+
agent, or several?** A candidate who runs ten agents in parallel is offering
|
|
91
|
+
something different from a candidate who is one, and the price follows from it.
|
|
92
|
+
|
|
93
|
+
Two contact-block keys carry it. Both are optional, like everything else here.
|
|
94
|
+
|
|
95
|
+
```markdown
|
|
96
|
+
# Athena
|
|
97
|
+
|
|
98
|
+
- **Email**: athena@example.com
|
|
99
|
+
- **Agents**: 10
|
|
100
|
+
- **Rate**: $100/hour/agent
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
- **`Agents`** is how many run in parallel. `1` is a real answer and worth stating
|
|
104
|
+
— an unstated capacity is not the same claim as a stated one.
|
|
105
|
+
- **`Rate`** is the hourly price. If it is marked per agent (`/agent`, `per agent`,
|
|
106
|
+
`each`), it prices one agent and the swarm total is the product. Without such a
|
|
107
|
+
marker it prices **the whole swarm**, because `$1,000/hour` from someone running
|
|
108
|
+
ten agents is a swarm price, and reading it per-agent would overstate the cost
|
|
109
|
+
tenfold.
|
|
110
|
+
|
|
111
|
+
A reader that understands both reports `10 agents · $100/hr each · $1,000/hr total`.
|
|
112
|
+
|
|
113
|
+
Degradation is the same as everywhere else in this format. No `Agents` key means the
|
|
114
|
+
capacity is unstated, which readers should say rather than assume: rendering nothing
|
|
115
|
+
where a number would go reads as "one agent" to anyone skimming, and that is the
|
|
116
|
+
wrong default for someone running ten. A `Rate` with no `Agents` is ignored, because
|
|
117
|
+
a price whose unit is unknown is not information — it is a guess an employer would
|
|
118
|
+
budget against.
|
|
119
|
+
|
|
120
|
+
`Sub-agents`, `Swarm`, `Parallelism` and `Capacity` are accepted as aliases for
|
|
121
|
+
`Agents`; `Price`, `Pricing`, `Cost` and `Hourly` for `Rate`.
|
|
122
|
+
|
|
87
123
|
## What is deliberately absent
|
|
88
124
|
|
|
89
125
|
**No required fields.** A document consisting of a name and three paragraphs is a
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
-- The inbox, and the invoices that travel through it.
|
|
2
|
+
--
|
|
3
|
+
-- A board where the only way to reach somebody is a public comment box gets
|
|
4
|
+
-- used as one: ugig.net's comments filled up with invoices, because an invoice
|
|
5
|
+
-- has to go *somewhere* and that was the only somewhere. So there is no public
|
|
6
|
+
-- commenting here at all. A conversation is private to the people in it, and
|
|
7
|
+
-- an invoice is a message in that conversation with money attached.
|
|
8
|
+
--
|
|
9
|
+
-- Two things are in the schema rather than in a validator:
|
|
10
|
+
--
|
|
11
|
+
-- - A message is bounded. 4000 characters is a long letter; it is not room
|
|
12
|
+
-- for a pasted document, which belongs on a resume or a listing.
|
|
13
|
+
-- - An invoice has one payee and one amount, and its status moves forward.
|
|
14
|
+
-- It is never edited after it is sent: a changed invoice is a new one.
|
|
15
|
+
|
|
16
|
+
-- A conversation. The subject is the one line the list page shows.
|
|
17
|
+
create table if not exists threads (
|
|
18
|
+
id uuid primary key default gen_random_uuid(),
|
|
19
|
+
subject text not null check (length(subject) between 1 and 140),
|
|
20
|
+
-- The listing this is about, when it is about one. Kept when the listing
|
|
21
|
+
-- is deleted: the conversation still happened.
|
|
22
|
+
job_id uuid references jobs (id) on delete set null,
|
|
23
|
+
created_by uuid not null references users (id) on delete cascade,
|
|
24
|
+
created_at timestamptz not null default now(),
|
|
25
|
+
-- Denormalised so the inbox sorts without touching messages.
|
|
26
|
+
last_message_at timestamptz not null default now()
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
-- Who is in it. A person is in a conversation either as themselves or as a
|
|
30
|
+
-- member of an employer; `org_id` says which, and is what the other side sees
|
|
31
|
+
-- as the name. Every member of the employer is a participant, so a message to
|
|
32
|
+
-- "Acme" reaches whoever at Acme is around.
|
|
33
|
+
create table if not exists thread_participants (
|
|
34
|
+
thread_id uuid not null references threads (id) on delete cascade,
|
|
35
|
+
user_id uuid not null references users (id) on delete cascade,
|
|
36
|
+
org_id uuid references organisations (id) on delete set null,
|
|
37
|
+
-- Unread is "a message newer than this". Null means never opened.
|
|
38
|
+
last_read_at timestamptz,
|
|
39
|
+
-- When this person was last emailed about this thread, so a burst of ten
|
|
40
|
+
-- messages is one email rather than ten.
|
|
41
|
+
notified_at timestamptz,
|
|
42
|
+
primary key (thread_id, user_id)
|
|
43
|
+
);
|
|
44
|
+
|
|
45
|
+
create index if not exists thread_participants_user_idx on thread_participants (user_id);
|
|
46
|
+
create index if not exists thread_participants_org_idx on thread_participants (org_id)
|
|
47
|
+
where org_id is not null;
|
|
48
|
+
create index if not exists threads_job_idx on threads (job_id) where job_id is not null;
|
|
49
|
+
|
|
50
|
+
-- An invoice. Its money is settled on CoinPay, to the payee's own wallet; the
|
|
51
|
+
-- board never holds funds. The row here is the source of truth for *which*
|
|
52
|
+
-- conversation it belongs to and *whether it has been paid*; the CoinPay
|
|
53
|
+
-- payment is the source of truth for the chain-level facts, and is re-minted
|
|
54
|
+
-- when a quote expires unpaid, so `coinpay_payment_id` changes over time and
|
|
55
|
+
-- `status` does not move backwards.
|
|
56
|
+
create table if not exists invoices (
|
|
57
|
+
id uuid primary key default gen_random_uuid(),
|
|
58
|
+
thread_id uuid not null references threads (id) on delete cascade,
|
|
59
|
+
-- Who gets paid. Always a person: a payout goes to a wallet somebody
|
|
60
|
+
-- connected, and an employer does not have one.
|
|
61
|
+
payee_id uuid not null references users (id) on delete cascade,
|
|
62
|
+
amount_usd numeric(12, 2) not null check (amount_usd > 0),
|
|
63
|
+
-- The chain the payee chose to be paid on, in CoinPay's spelling:
|
|
64
|
+
-- BTC, ETH, SOL, USDC_POL and so on.
|
|
65
|
+
currency text not null,
|
|
66
|
+
-- The payee's address for that chain, copied at send time. An invoice
|
|
67
|
+
-- settles to the wallet it was sent with, whatever is connected later.
|
|
68
|
+
wallet_address text not null,
|
|
69
|
+
description text not null default '' check (length(description) <= 1000),
|
|
70
|
+
status text not null default 'sent'
|
|
71
|
+
check (status in ('sent', 'paid', 'cancelled')),
|
|
72
|
+
coinpay_payment_id text,
|
|
73
|
+
payment_address text,
|
|
74
|
+
amount_crypto text,
|
|
75
|
+
payment_expires_at timestamptz,
|
|
76
|
+
paid_at timestamptz,
|
|
77
|
+
paid_by uuid references users (id) on delete set null,
|
|
78
|
+
tx_hash text,
|
|
79
|
+
created_at timestamptz not null default now(),
|
|
80
|
+
updated_at timestamptz not null default now()
|
|
81
|
+
);
|
|
82
|
+
|
|
83
|
+
create index if not exists invoices_thread_idx on invoices (thread_id, created_at desc);
|
|
84
|
+
create index if not exists invoices_payee_idx on invoices (payee_id, created_at desc);
|
|
85
|
+
-- The webhook looks a payment up by CoinPay's id and nothing else.
|
|
86
|
+
create unique index if not exists invoices_payment_key on invoices (coinpay_payment_id)
|
|
87
|
+
where coinpay_payment_id is not null;
|
|
88
|
+
|
|
89
|
+
-- A message. `kind` says whether it is words or an invoice; an invoice message
|
|
90
|
+
-- carries the invoice and its body is the description, so a thread reads
|
|
91
|
+
-- top to bottom without joining.
|
|
92
|
+
create table if not exists messages (
|
|
93
|
+
id uuid primary key default gen_random_uuid(),
|
|
94
|
+
thread_id uuid not null references threads (id) on delete cascade,
|
|
95
|
+
sender_id uuid not null references users (id) on delete cascade,
|
|
96
|
+
kind text not null default 'text' check (kind in ('text', 'invoice')),
|
|
97
|
+
body text not null check (length(body) between 1 and 4000),
|
|
98
|
+
invoice_id uuid references invoices (id) on delete set null,
|
|
99
|
+
created_at timestamptz not null default now(),
|
|
100
|
+
constraint messages_invoice_kind check (
|
|
101
|
+
(kind = 'invoice' and invoice_id is not null) or (kind = 'text' and invoice_id is null)
|
|
102
|
+
)
|
|
103
|
+
);
|
|
104
|
+
|
|
105
|
+
create index if not exists messages_thread_idx on messages (thread_id, created_at);
|
|
106
|
+
|
|
107
|
+
-- A CoinPay account somebody connected, so the board can read which wallets
|
|
108
|
+
-- they can be paid to. The tokens are theirs, for their account: the board
|
|
109
|
+
-- reads `userinfo` with them and nothing else.
|
|
110
|
+
--
|
|
111
|
+
-- One CoinPay account attaches to one person here, and the unique index is
|
|
112
|
+
-- what says so. Without it the first account to connect a wallet would be the
|
|
113
|
+
-- one every later profile quietly pays out to.
|
|
114
|
+
create table if not exists coinpay_accounts (
|
|
115
|
+
user_id uuid primary key references users (id) on delete cascade,
|
|
116
|
+
coinpay_sub text not null unique,
|
|
117
|
+
email text,
|
|
118
|
+
name text,
|
|
119
|
+
access_token text not null,
|
|
120
|
+
refresh_token text,
|
|
121
|
+
scope text not null default '',
|
|
122
|
+
expires_at timestamptz not null,
|
|
123
|
+
-- What userinfo last said: [{ address, chain, label }]. Refreshed on
|
|
124
|
+
-- connect and on request, never trusted to be more current than that.
|
|
125
|
+
wallets jsonb not null default '[]'::jsonb,
|
|
126
|
+
connected_at timestamptz not null default now(),
|
|
127
|
+
updated_at timestamptz not null default now()
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
-- An authorization in flight. Server-side rather than in a cookie so the same
|
|
131
|
+
-- flow works from a terminal, and so a state is single-use by deletion.
|
|
132
|
+
create table if not exists coinpay_oauth_states (
|
|
133
|
+
state text primary key,
|
|
134
|
+
user_id uuid not null references users (id) on delete cascade,
|
|
135
|
+
code_verifier text not null,
|
|
136
|
+
redirect text,
|
|
137
|
+
expires_at timestamptz not null
|
|
138
|
+
);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@profullstack/agenticjobs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "An agent-friendly job board you self-host. It posts its own jobs, never scrapes anyone else's, and answers on every surface: web, API, MCP, CLI, TUI, desktop and PWA. Instances find each other through an open directory.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -29,7 +29,6 @@
|
|
|
29
29
|
"engines": {
|
|
30
30
|
"node": ">=24"
|
|
31
31
|
},
|
|
32
|
-
"packageManager": "pnpm@11.18.0",
|
|
33
32
|
"bin": {
|
|
34
33
|
"agenticjobs": "./bin/agenticjobs.mjs",
|
|
35
34
|
"agenticjobs-mcp": "./bin/agenticjobs-mcp.mjs"
|
|
@@ -43,20 +42,6 @@
|
|
|
43
42
|
"README.md",
|
|
44
43
|
"LICENSE"
|
|
45
44
|
],
|
|
46
|
-
"scripts": {
|
|
47
|
-
"build": "tsc -p tsconfig.json",
|
|
48
|
-
"clean": "rm -rf dist",
|
|
49
|
-
"dev": "node --env-file-if-exists=.env --watch dist/cli/index.js serve",
|
|
50
|
-
"start": "node --env-file-if-exists=.env dist/cli/index.js serve",
|
|
51
|
-
"migrate": "node --env-file-if-exists=.env dist/db/migrate.js",
|
|
52
|
-
"seed": "node --env-file-if-exists=.env dist/db/seed.js",
|
|
53
|
-
"tui": "node --env-file-if-exists=.env dist/cli/index.js tui",
|
|
54
|
-
"test": "pnpm run build && node --test \"test/*.test.ts\"",
|
|
55
|
-
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
56
|
-
"format": "prettier --write .",
|
|
57
|
-
"prepublishOnly": "pnpm run clean && pnpm run build",
|
|
58
|
-
"test:only": "node --test \"test/*.test.ts\""
|
|
59
|
-
},
|
|
60
45
|
"dependencies": {
|
|
61
46
|
"@hono/node-server": "^1.14.0",
|
|
62
47
|
"@profullstack/emailer": "^1.0.3",
|
|
@@ -89,5 +74,18 @@
|
|
|
89
74
|
"default": "./dist/mcp/server.js"
|
|
90
75
|
},
|
|
91
76
|
"./package.json": "./package.json"
|
|
77
|
+
},
|
|
78
|
+
"scripts": {
|
|
79
|
+
"build": "tsc -p tsconfig.json",
|
|
80
|
+
"clean": "rm -rf dist",
|
|
81
|
+
"dev": "node --env-file-if-exists=.env --watch dist/cli/index.js serve",
|
|
82
|
+
"start": "node --env-file-if-exists=.env dist/cli/index.js serve",
|
|
83
|
+
"migrate": "node --env-file-if-exists=.env dist/db/migrate.js",
|
|
84
|
+
"seed": "node --env-file-if-exists=.env dist/db/seed.js",
|
|
85
|
+
"tui": "node --env-file-if-exists=.env dist/cli/index.js tui",
|
|
86
|
+
"test": "pnpm run build && node --test \"test/*.test.ts\"",
|
|
87
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
88
|
+
"format": "prettier --write .",
|
|
89
|
+
"test:only": "node --test \"test/*.test.ts\""
|
|
92
90
|
}
|
|
93
|
-
}
|
|
91
|
+
}
|
package/web/public/app.css
CHANGED
|
@@ -111,7 +111,15 @@ a:hover {
|
|
|
111
111
|
flex-wrap: wrap;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
/*
|
|
115
|
+
* `:not(.btn)` is load bearing. `.nav a` outranks `.btn`, so "Post a job" and
|
|
116
|
+
* "Sign in" used to paint --muted-foreground on the --primary background:
|
|
117
|
+
* two nearly identical lightnesses (0.53 on 0.52 light, 0.71 on 0.72 dark),
|
|
118
|
+
* so the label was invisible until the hover rule repainted it as a plain nav
|
|
119
|
+
* link. Excluding buttons here leaves them to .btn, which pairs --primary
|
|
120
|
+
* with --primary-foreground and stays legible in both states.
|
|
121
|
+
*/
|
|
122
|
+
.nav a:not(.btn) {
|
|
115
123
|
color: var(--muted-foreground);
|
|
116
124
|
text-decoration: none;
|
|
117
125
|
font-size: 0.9rem;
|
|
@@ -120,8 +128,8 @@ a:hover {
|
|
|
120
128
|
border-radius: calc(var(--radius) - 4px);
|
|
121
129
|
}
|
|
122
130
|
|
|
123
|
-
.nav a:hover,
|
|
124
|
-
.nav a[aria-current='page'] {
|
|
131
|
+
.nav a:not(.btn):hover,
|
|
132
|
+
.nav a:not(.btn)[aria-current='page'] {
|
|
125
133
|
color: var(--foreground);
|
|
126
134
|
background: var(--secondary);
|
|
127
135
|
}
|
|
@@ -177,6 +185,33 @@ main {
|
|
|
177
185
|
}
|
|
178
186
|
}
|
|
179
187
|
|
|
188
|
+
/*
|
|
189
|
+
* The sidebar is a fixed 20rem track, and what goes in it is exactly the kind
|
|
190
|
+
* of text that cannot break on its own: an email address, a URL, the API line
|
|
191
|
+
* an agent is meant to copy, a skill tag. With no wrapping rule each one is a
|
|
192
|
+
* single word wider than the card, and it walks out over the card's border
|
|
193
|
+
* (the candidate page's contact block did). `anywhere` lets these break at
|
|
194
|
+
* any character; it inherits, so one rule on the aside covers every card.
|
|
195
|
+
*
|
|
196
|
+
* A code block in the sidebar wraps instead of scrolling. A 20rem scroller
|
|
197
|
+
* shows "GET https://example.com/api/v1/cand" and hides the part that
|
|
198
|
+
* matters; the wrapped line is still one line to copy. The page-wide
|
|
199
|
+
* `.code-block` rule keeps its `overflow-x: auto` for the docs, where lines
|
|
200
|
+
* are meant to stay lines.
|
|
201
|
+
*/
|
|
202
|
+
.grid-2 > aside {
|
|
203
|
+
overflow-wrap: anywhere;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
.grid-2 > aside .code-block {
|
|
207
|
+
white-space: pre-wrap;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.grid-2 > aside .badge {
|
|
211
|
+
white-space: normal;
|
|
212
|
+
text-align: left;
|
|
213
|
+
}
|
|
214
|
+
|
|
180
215
|
.stack {
|
|
181
216
|
display: flex;
|
|
182
217
|
flex-direction: column;
|
|
@@ -859,3 +894,111 @@ a.badge-plain:hover .badge {
|
|
|
859
894
|
.update-link {
|
|
860
895
|
overflow-wrap: anywhere;
|
|
861
896
|
}
|
|
897
|
+
|
|
898
|
+
/* --- inbox ------------------------------------------------------------- */
|
|
899
|
+
|
|
900
|
+
.nav-count {
|
|
901
|
+
display: inline-block;
|
|
902
|
+
min-width: 1.3em;
|
|
903
|
+
padding: 0 0.35em;
|
|
904
|
+
border-radius: 999px;
|
|
905
|
+
background: var(--primary);
|
|
906
|
+
color: var(--primary-foreground);
|
|
907
|
+
font-size: 0.75em;
|
|
908
|
+
line-height: 1.6;
|
|
909
|
+
text-align: center;
|
|
910
|
+
}
|
|
911
|
+
|
|
912
|
+
.thread-list,
|
|
913
|
+
.message-list {
|
|
914
|
+
list-style: none;
|
|
915
|
+
margin: 0;
|
|
916
|
+
padding: 0;
|
|
917
|
+
display: flex;
|
|
918
|
+
flex-direction: column;
|
|
919
|
+
gap: 0.75rem;
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
.thread-subject {
|
|
923
|
+
margin: 0.35rem 0 0.2rem;
|
|
924
|
+
font-weight: 600;
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
.thread-preview {
|
|
928
|
+
margin: 0;
|
|
929
|
+
overflow-wrap: anywhere;
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
.message {
|
|
933
|
+
border: 1px solid var(--border);
|
|
934
|
+
border-radius: var(--radius);
|
|
935
|
+
padding: 0.9rem 1rem;
|
|
936
|
+
background: var(--card);
|
|
937
|
+
max-width: 92%;
|
|
938
|
+
scroll-margin-top: 5rem;
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
/* Yours sit to the right, theirs to the left, so a long thread scans. */
|
|
942
|
+
.message.mine {
|
|
943
|
+
align-self: flex-end;
|
|
944
|
+
background: color-mix(in oklab, var(--primary) 8%, var(--card));
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
.message-meta {
|
|
948
|
+
margin: 0 0 0.35rem;
|
|
949
|
+
}
|
|
950
|
+
|
|
951
|
+
.message-body {
|
|
952
|
+
margin: 0;
|
|
953
|
+
/* Typed in a textarea, so the line breaks are the author's. */
|
|
954
|
+
white-space: pre-wrap;
|
|
955
|
+
overflow-wrap: anywhere;
|
|
956
|
+
}
|
|
957
|
+
|
|
958
|
+
.invoice {
|
|
959
|
+
border: 1px dashed var(--border);
|
|
960
|
+
border-radius: calc(var(--radius) - 2px);
|
|
961
|
+
padding: 0.75rem 0.9rem;
|
|
962
|
+
display: flex;
|
|
963
|
+
flex-direction: column;
|
|
964
|
+
gap: 0.5rem;
|
|
965
|
+
/* Addresses and transaction hashes are one word each. */
|
|
966
|
+
overflow-wrap: anywhere;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
.invoice-amount {
|
|
970
|
+
font-size: 1.25rem;
|
|
971
|
+
font-weight: 700;
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
.invoice-description {
|
|
975
|
+
margin: 0;
|
|
976
|
+
white-space: pre-wrap;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
.invoice-form > summary {
|
|
980
|
+
cursor: pointer;
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
.wallet-list code {
|
|
984
|
+
overflow-wrap: anywhere;
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
.table {
|
|
988
|
+
width: 100%;
|
|
989
|
+
border-collapse: collapse;
|
|
990
|
+
font-size: 0.9rem;
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
.table th,
|
|
994
|
+
.table td {
|
|
995
|
+
text-align: left;
|
|
996
|
+
padding: 0.5rem 0.6rem;
|
|
997
|
+
border-bottom: 1px solid var(--border);
|
|
998
|
+
vertical-align: top;
|
|
999
|
+
}
|
|
1000
|
+
|
|
1001
|
+
.table th {
|
|
1002
|
+
color: var(--muted-foreground);
|
|
1003
|
+
font-weight: 500;
|
|
1004
|
+
}
|
package/web/public/sw.js
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
* drifted, which is the only version of this rule that survives contact.
|
|
14
14
|
*/
|
|
15
15
|
|
|
16
|
-
const VERSION = '
|
|
16
|
+
const VERSION = 'f53a4407';
|
|
17
17
|
const SHELL = `shell-${VERSION}`;
|
|
18
18
|
const ASSETS = ['/assets/app.css', '/assets/tokens.css', '/assets/icon.svg'];
|
|
19
19
|
|