cardinal-ai 0.0.1 → 0.2.3

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.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +21 -0
  3. data/README.md +50 -29
  4. data/Rakefile +6 -0
  5. data/app/assets/stylesheets/application.css +10 -0
  6. data/app/assets/stylesheets/cardinal.css +514 -0
  7. data/app/controllers/application_controller.rb +7 -0
  8. data/app/controllers/boards_controller.rb +5 -0
  9. data/app/controllers/cards_controller.rb +129 -0
  10. data/app/controllers/columns_controller.rb +95 -0
  11. data/app/controllers/messages_controller.rb +25 -0
  12. data/app/controllers/runs_controller.rb +58 -0
  13. data/app/helpers/application_helper.rb +35 -0
  14. data/app/javascript/application.js +2 -0
  15. data/app/javascript/controllers/application.js +7 -0
  16. data/app/javascript/controllers/autosave_controller.js +28 -0
  17. data/app/javascript/controllers/board_column_controller.js +96 -0
  18. data/app/javascript/controllers/clipboard_controller.js +18 -0
  19. data/app/javascript/controllers/composer_controller.js +10 -0
  20. data/app/javascript/controllers/index.js +3 -0
  21. data/app/javascript/controllers/modal_controller.js +43 -0
  22. data/app/javascript/controllers/scroll_controller.js +44 -0
  23. data/app/javascript/controllers/tags_controller.js +49 -0
  24. data/app/javascript/controllers/theme_controller.js +43 -0
  25. data/app/javascript/controllers/tooltip_controller.js +37 -0
  26. data/app/jobs/ai_task_job.rb +26 -0
  27. data/app/jobs/application_job.rb +7 -0
  28. data/app/jobs/assistant_reply_job.rb +132 -0
  29. data/app/jobs/mark_pr_ready_job.rb +18 -0
  30. data/app/jobs/merge_pr_job.rb +27 -0
  31. data/app/jobs/resume_run_job.rb +30 -0
  32. data/app/jobs/start_run_job.rb +13 -0
  33. data/app/mailers/application_mailer.rb +4 -0
  34. data/app/models/agent_session.rb +8 -0
  35. data/app/models/application_record.rb +3 -0
  36. data/app/models/artifact.rb +8 -0
  37. data/app/models/board.rb +60 -0
  38. data/app/models/card.rb +83 -0
  39. data/app/models/column.rb +83 -0
  40. data/app/models/event.rb +44 -0
  41. data/app/models/run.rb +28 -0
  42. data/app/services/agent/runner.rb +379 -0
  43. data/app/services/agent/workspace.rb +138 -0
  44. data/app/services/card_transition.rb +97 -0
  45. data/app/services/claude_cli.rb +89 -0
  46. data/app/services/rules/compiler.rb +55 -0
  47. data/app/services/rules.rb +67 -0
  48. data/app/services/run_sweeper.rb +52 -0
  49. data/app/views/boards/show.html.erb +79 -0
  50. data/app/views/cards/_card.html.erb +48 -0
  51. data/app/views/cards/_detail.html.erb +190 -0
  52. data/app/views/cards/_tag_picker.html.erb +12 -0
  53. data/app/views/cards/new.html.erb +35 -0
  54. data/app/views/cards/show.html.erb +3 -0
  55. data/app/views/columns/_column.html.erb +25 -0
  56. data/app/views/columns/edit.html.erb +126 -0
  57. data/app/views/events/_event.html.erb +29 -0
  58. data/app/views/layouts/application.html.erb +46 -0
  59. data/app/views/layouts/mailer.html.erb +13 -0
  60. data/app/views/layouts/mailer.text.erb +1 -0
  61. data/app/views/pwa/manifest.json.erb +22 -0
  62. data/app/views/pwa/service-worker.js +26 -0
  63. data/bin/rails +4 -0
  64. data/bin/rake +4 -0
  65. data/cardinal.md +686 -0
  66. data/config/application.rb +60 -0
  67. data/config/boot.rb +13 -0
  68. data/config/bundler-audit.yml +5 -0
  69. data/config/cable.yml +13 -0
  70. data/config/ci.rb +20 -0
  71. data/config/credentials.yml.enc +1 -0
  72. data/config/database.yml +31 -0
  73. data/config/environment.rb +5 -0
  74. data/config/environments/development.rb +78 -0
  75. data/config/environments/production.rb +89 -0
  76. data/config/environments/test.rb +53 -0
  77. data/config/importmap.rb +6 -0
  78. data/config/initializers/assets.rb +7 -0
  79. data/config/initializers/cardinal_bootstrap.rb +12 -0
  80. data/config/initializers/cardinal_instance.rb +20 -0
  81. data/config/initializers/content_security_policy.rb +29 -0
  82. data/config/initializers/filter_parameter_logging.rb +8 -0
  83. data/config/initializers/inflections.rb +16 -0
  84. data/config/initializers/run_sweeper.rb +17 -0
  85. data/config/locales/en.yml +31 -0
  86. data/config/puma.rb +42 -0
  87. data/config/routes.rb +22 -0
  88. data/config/storage.yml +27 -0
  89. data/config.ru +6 -0
  90. data/db/migrate/20260703000001_create_cardinal_schema.rb +78 -0
  91. data/db/migrate/20260703000002_add_agent_runner_fields.rb +7 -0
  92. data/db/migrate/20260704000001_add_parent_to_cards.rb +5 -0
  93. data/db/migrate/20260704000002_add_assistant_session_to_cards.rb +5 -0
  94. data/db/seeds.rb +19 -0
  95. data/docker/agent/Dockerfile +16 -0
  96. data/exe/cardinal +111 -0
  97. data/lib/cardinal/version.rb +1 -1
  98. data/public/400.html +135 -0
  99. data/public/404.html +135 -0
  100. data/public/406-unsupported-browser.html +135 -0
  101. data/public/422.html +135 -0
  102. data/public/500.html +135 -0
  103. data/public/icon.png +0 -0
  104. data/public/icon.svg +3 -0
  105. data/public/robots.txt +1 -0
  106. data/vendor/javascript/sortablejs.js +3378 -0
  107. metadata +235 -9
@@ -0,0 +1,78 @@
1
+ class CreateCardinalSchema < ActiveRecord::Migration[8.1]
2
+ def change
3
+ create_table :boards do |t|
4
+ t.string :name, null: false
5
+ t.string :repo_url
6
+ t.string :default_branch, null: false, default: "main"
7
+ t.timestamps
8
+ end
9
+
10
+ create_table :columns do |t|
11
+ t.references :board, null: false, foreign_key: true
12
+ t.string :name, null: false
13
+ t.integer :position, null: false
14
+ t.string :archetype, null: false, default: "inbox"
15
+ t.json :policy, null: false, default: {}
16
+ t.timestamps
17
+ end
18
+ add_index :columns, [:board_id, :position]
19
+
20
+ create_table :cards do |t|
21
+ t.references :board, null: false, foreign_key: true
22
+ t.references :column, null: false, foreign_key: true
23
+ t.integer :number, null: false
24
+ t.string :title, null: false
25
+ t.text :description
26
+ t.json :tags, null: false, default: []
27
+ t.integer :position, null: false
28
+ t.string :status, null: false, default: "draft"
29
+ t.string :branch_name
30
+ t.string :pr_url
31
+ t.string :pr_state
32
+ t.timestamps
33
+ end
34
+ add_index :cards, [:board_id, :number], unique: true
35
+ add_index :cards, [:column_id, :position]
36
+
37
+ create_table :agent_sessions do |t|
38
+ t.references :card, null: false, foreign_key: true
39
+ t.string :status, null: false, default: "provisioning"
40
+ t.string :workspace_ref
41
+ t.string :model
42
+ t.json :config, null: false, default: {}
43
+ t.timestamps
44
+ end
45
+
46
+ create_table :runs do |t|
47
+ t.references :agent_session, null: false, foreign_key: true
48
+ t.string :status, null: false, default: "queued"
49
+ t.json :briefing, null: false, default: {}
50
+ t.text :result_summary
51
+ t.integer :input_tokens, null: false, default: 0
52
+ t.integer :output_tokens, null: false, default: 0
53
+ t.decimal :cost, precision: 10, scale: 4, null: false, default: 0
54
+ t.datetime :started_at
55
+ t.datetime :finished_at
56
+ t.datetime :heartbeat_at
57
+ t.timestamps
58
+ end
59
+
60
+ create_table :events do |t|
61
+ t.references :card, null: false, foreign_key: true
62
+ t.references :run, foreign_key: true
63
+ t.string :kind, null: false
64
+ t.string :actor, null: false, default: "system"
65
+ t.json :payload, null: false, default: {}
66
+ t.timestamps
67
+ end
68
+ add_index :events, [:card_id, :created_at]
69
+
70
+ create_table :artifacts do |t|
71
+ t.references :run, null: false, foreign_key: true
72
+ t.string :kind, null: false
73
+ t.string :name, null: false
74
+ t.json :payload, null: false, default: {}
75
+ t.timestamps
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,7 @@
1
+ class AddAgentRunnerFields < ActiveRecord::Migration[8.1]
2
+ def change
3
+ add_column :runs, :external_session_id, :string
4
+ add_column :runs, :phase, :string, null: false, default: "execute"
5
+ add_column :boards, :local_path, :string
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ class AddParentToCards < ActiveRecord::Migration[8.1]
2
+ def change
3
+ add_reference :cards, :parent, foreign_key: { to_table: :cards }, null: true
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddAssistantSessionToCards < ActiveRecord::Migration[8.1]
2
+ def change
3
+ add_column :cards, :assistant_session_id, :string
4
+ end
5
+ end
data/db/seeds.rb ADDED
@@ -0,0 +1,19 @@
1
+ # Engine-development seeds only. Portable instances (`cardinal up` in another
2
+ # repo) are bootstrapped by config/initializers/cardinal_bootstrap.rb instead.
3
+ return if ENV["CARDINAL_TARGET_REPO"].present?
4
+
5
+ board = Board.find_or_create_by!(name: "Cardinal") do |b|
6
+ b.repo_url = "git@github.com:palamedes/cardinal.git"
7
+ b.default_branch = "main"
8
+ b.local_path = Rails.root.to_s
9
+ end
10
+
11
+ Board::DEFAULT_COLUMNS.each_with_index do |attrs, index|
12
+ board.columns.find_or_create_by!(name: attrs[:name]) do |c|
13
+ c.position = index
14
+ c.archetype = attrs[:archetype]
15
+ c.policy = attrs[:policy]
16
+ end
17
+ end
18
+
19
+ puts "Seeded board '#{board.name}' with #{board.columns.count} columns."
@@ -0,0 +1,16 @@
1
+ # The cardinal-agent image: what a card's worker agent runs inside when
2
+ # CARDINAL_WORKSPACE=container (cardinal.md §13). Build with:
3
+ # docker build -t cardinal-agent docker/agent
4
+ FROM node:22-slim
5
+
6
+ RUN apt-get update && apt-get install -y --no-install-recommends \
7
+ git ca-certificates curl ripgrep \
8
+ && rm -rf /var/lib/apt/lists/* \
9
+ && npm install -g @anthropic-ai/claude-code
10
+
11
+ RUN useradd -m agent
12
+ USER agent
13
+ WORKDIR /workspace/repo
14
+
15
+ # Auth comes from ANTHROPIC_API_KEY injected at `docker run` by the runner.
16
+ ENTRYPOINT []
data/exe/cardinal ADDED
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ # cardinal — spin up a Cardinal AI board for the repo you're standing in.
5
+ #
6
+ # cardinal # or `cardinal up` — first run links a Claude account
7
+ # cardinal login # redo the account link (switch accounts)
8
+ # cardinal logout # unlink this instance's account
9
+ #
10
+ # Each instance carries its OWN Claude identity, stored in ./.cardinal/claude/.
11
+ # Escape hatch: CARDINAL_INHERIT_AUTH=1 uses the machine's claude login.
12
+ # Everything lives in ./.cardinal/ — hidden from the host repo via
13
+ # .git/info/exclude, never committed.
14
+
15
+ require "fileutils"
16
+
17
+ HOME_DIR = File.expand_path("..", __dir__)
18
+ TARGET = Dir.pwd
19
+ AUTH_DIR = File.join(TARGET, ".cardinal", "claude")
20
+ TOKEN_FILE = File.join(AUTH_DIR, "oauth-token")
21
+
22
+ def say(msg) = puts("cardinal ▸ #{msg}")
23
+ def die(msg) = abort("cardinal: #{msg}")
24
+
25
+ cmd = ARGV[0] || "up"
26
+ die "#{TARGET} is not a git repository" unless File.directory?(File.join(TARGET, ".git"))
27
+
28
+ case cmd
29
+ when "logout"
30
+ FileUtils.rm_rf(AUTH_DIR)
31
+ say "account unlinked for #{File.basename(TARGET)}"
32
+ exit 0
33
+ when "login"
34
+ FileUtils.rm_f(TOKEN_FILE)
35
+ when "up" # continue
36
+ else
37
+ die "usage: cardinal [up|login|logout]"
38
+ end
39
+
40
+ # Hide .cardinal/ from the host repo without touching its .gitignore.
41
+ exclude = File.join(TARGET, ".git", "info", "exclude")
42
+ FileUtils.mkdir_p(File.dirname(exclude))
43
+ unless File.exist?(exclude) && File.readlines(exclude).any? { |l| l.strip == ".cardinal/" }
44
+ File.open(exclude, "a") { |f| f.puts ".cardinal/" }
45
+ end
46
+ FileUtils.mkdir_p(File.join(TARGET, ".cardinal", "tmp"))
47
+
48
+ # ── Per-instance Claude identity ────────────────────────────────────────────
49
+ if ENV["CARDINAL_INHERIT_AUTH"] == "1"
50
+ say "using this machine's claude login (CARDINAL_INHERIT_AUTH=1)"
51
+ ENV["CARDINAL_AUTH"] = "inherited"
52
+ else
53
+ unless File.size?(TOKEN_FILE)
54
+ say "no Claude account is linked to this board yet"
55
+ say "starting the account link — pick the account this board should work as"
56
+ FileUtils.mkdir_p(AUTH_DIR)
57
+ File.chmod(0o700, AUTH_DIR)
58
+
59
+ # setup-token is interactive (browser hop, sometimes a pasted code):
60
+ # stream its output to the terminal while capturing it for the token.
61
+ buffer = +""
62
+ reader, writer = IO.pipe
63
+ pid = spawn({ "CLAUDE_CONFIG_DIR" => AUTH_DIR }, "claude", "setup-token",
64
+ out: writer, err: writer)
65
+ writer.close
66
+ begin
67
+ loop do
68
+ chunk = reader.readpartial(4096)
69
+ $stdout.write(chunk)
70
+ $stdout.flush
71
+ buffer << chunk
72
+ end
73
+ rescue EOFError
74
+ # stream ended
75
+ end
76
+ Process.wait(pid)
77
+ die "account link failed — try again, or CARDINAL_INHERIT_AUTH=1 to use the machine login" unless $?.success?
78
+
79
+ token = buffer.scan(/sk-ant-[A-Za-z0-9_\-]+/).last
80
+ die "no token found in setup output" unless token
81
+ File.write(TOKEN_FILE, token)
82
+ File.chmod(0o600, TOKEN_FILE)
83
+ say "account linked (stored in .cardinal/claude/, local-only)"
84
+ end
85
+ ENV["CLAUDE_CONFIG_DIR"] = AUTH_DIR
86
+ ENV["CLAUDE_CODE_OAUTH_TOKEN"] = File.read(TOKEN_FILE).strip
87
+ ENV["CARDINAL_AUTH"] = "dedicated"
88
+ end
89
+
90
+ ENV["CARDINAL_GEM"] = "1"
91
+ ENV["RAILS_ENV"] ||= "development"
92
+ ENV["CARDINAL_TARGET_REPO"] = TARGET
93
+ ENV["CARDINAL_DATA_DIR"] = File.join(TARGET, ".cardinal")
94
+ ENV["PORT"] ||= "4000"
95
+
96
+ say "board for #{File.basename(TARGET)} — data in .cardinal/, ui on http://localhost:#{ENV["PORT"]}"
97
+
98
+ Dir.chdir(HOME_DIR)
99
+ system(RbConfig.ruby, File.join(HOME_DIR, "bin", "rails"), "db:prepare") || die("database preparation failed")
100
+ if ENV["CARDINAL_NO_SERVER"] == "1"
101
+ say "prepared (no-server mode)"
102
+ exit 0
103
+ end
104
+
105
+ # Boot puma directly (not `rails server`, which insists on creating tmp/
106
+ # scaffolding inside the engine/gem directory — read-only for sudo installs).
107
+ ENV["PIDFILE"] = File.join(TARGET, ".cardinal", "tmp", "server.pid")
108
+ ENV["CARDINAL_SWEEPER"] = "1" # the sweeper initializer keys off Rails::Server otherwise
109
+ exec(RbConfig.ruby, "-S", "puma",
110
+ "-b", "tcp://0.0.0.0:#{ENV["PORT"]}",
111
+ File.join(HOME_DIR, "config.ru"))
@@ -1,3 +1,3 @@
1
1
  module Cardinal
2
- VERSION = "0.0.1"
2
+ VERSION = "0.2.3"
3
3
  end
data/public/400.html ADDED
@@ -0,0 +1,135 @@
1
+ <!doctype html>
2
+
3
+ <html lang="en">
4
+
5
+ <head>
6
+
7
+ <title>The server cannot process the request due to a client error (400 Bad Request)</title>
8
+
9
+ <meta charset="utf-8">
10
+ <meta name="viewport" content="initial-scale=1, width=device-width">
11
+ <meta name="robots" content="noindex, nofollow">
12
+
13
+ <style>
14
+
15
+ *, *::before, *::after {
16
+ box-sizing: border-box;
17
+ }
18
+
19
+ * {
20
+ margin: 0;
21
+ }
22
+
23
+ html {
24
+ font-size: 16px;
25
+ }
26
+
27
+ body {
28
+ background: #FFF;
29
+ color: #261B23;
30
+ display: grid;
31
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Aptos, Roboto, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
32
+ font-size: clamp(1rem, 2.5vw, 2rem);
33
+ -webkit-font-smoothing: antialiased;
34
+ font-style: normal;
35
+ font-weight: 400;
36
+ letter-spacing: -0.0025em;
37
+ line-height: 1.4;
38
+ min-height: 100dvh;
39
+ place-items: center;
40
+ text-rendering: optimizeLegibility;
41
+ -webkit-text-size-adjust: 100%;
42
+ }
43
+
44
+ #error-description {
45
+ fill: #d30001;
46
+ }
47
+
48
+ #error-id {
49
+ fill: #f0eff0;
50
+ }
51
+
52
+ @media (prefers-color-scheme: dark) {
53
+ body {
54
+ background: #101010;
55
+ color: #e0e0e0;
56
+ }
57
+
58
+ #error-description {
59
+ fill: #FF6161;
60
+ }
61
+
62
+ #error-id {
63
+ fill: #2c2c2c;
64
+ }
65
+ }
66
+
67
+ a {
68
+ color: inherit;
69
+ font-weight: 700;
70
+ text-decoration: underline;
71
+ text-underline-offset: 0.0925em;
72
+ }
73
+
74
+ b, strong {
75
+ font-weight: 700;
76
+ }
77
+
78
+ i, em {
79
+ font-style: italic;
80
+ }
81
+
82
+ main {
83
+ display: grid;
84
+ gap: 1em;
85
+ padding: 2em;
86
+ place-items: center;
87
+ text-align: center;
88
+ }
89
+
90
+ main header {
91
+ width: min(100%, 12em);
92
+ }
93
+
94
+ main header svg {
95
+ height: auto;
96
+ max-width: 100%;
97
+ width: 100%;
98
+ }
99
+
100
+ main article {
101
+ width: min(100%, 30em);
102
+ }
103
+
104
+ main article p {
105
+ font-size: 75%;
106
+ }
107
+
108
+ main article br {
109
+ display: none;
110
+
111
+ @media(min-width: 48em) {
112
+ display: inline;
113
+ }
114
+ }
115
+
116
+ </style>
117
+
118
+ </head>
119
+
120
+ <body>
121
+
122
+ <!-- This file lives in public/400.html -->
123
+
124
+ <main>
125
+ <header>
126
+ <svg height="172" viewBox="0 0 480 172" width="480" xmlns="http://www.w3.org/2000/svg"><path d="m124.48 3.00509-45.6889 100.02991h26.2239v-28.1168h38.119v28.1168h21.628v35.145h-21.628v30.82h-37.308v-30.82h-72.1833v-31.901l50.2851-103.27391zm115.583 168.69891c-40.822 0-64.884-35.146-64.884-85.7015 0-50.5554 24.062-85.700907 64.884-85.700907 40.823 0 64.884 35.145507 64.884 85.700907 0 50.5555-24.061 85.7015-64.884 85.7015zm0-133.2831c-17.572 0-22.709 21.8984-22.709 47.5816 0 25.6835 5.137 47.5815 22.709 47.5815 17.303 0 22.71-21.898 22.71-47.5815 0-25.6832-5.407-47.5816-22.71-47.5816zm140.456 133.2831c-40.823 0-64.884-35.146-64.884-85.7015 0-50.5554 24.061-85.700907 64.884-85.700907 40.822 0 64.884 35.145507 64.884 85.700907 0 50.5555-24.062 85.7015-64.884 85.7015zm0-133.2831c-17.573 0-22.71 21.8984-22.71 47.5816 0 25.6835 5.137 47.5815 22.71 47.5815 17.302 0 22.709-21.898 22.709-47.5815 0-25.6832-5.407-47.5816-22.709-47.5816z" id="error-id"/><path d="m123.606 85.4445c3.212 1.0523 5.538 4.2089 5.538 8.0301 0 6.1472-4.209 9.5254-11.298 9.5254h-15.617v-34.0033h14.565c7.089 0 11.353 3.1566 11.353 9.2484 0 3.6551-2.049 6.3134-4.541 7.1994zm-12.904-2.9905h5.095c2.603 0 3.988-.9968 3.988-3.1013 0-2.1044-1.385-3.0459-3.988-3.0459h-5.095zm0 6.6456v6.5902h5.981c2.492 0 3.877-1.3291 3.877-3.2674 0-2.049-1.385-3.3228-3.877-3.3228zm43.786 13.9004h-8.362v-1.274c-.831.831-3.323 1.717-5.981 1.717-4.929 0-9.083-2.769-9.083-8.0301 0-4.818 4.154-7.9193 9.581-7.9193 2.049 0 4.486.6646 5.483 1.3845v-1.606c0-1.606-.942-2.9905-3.046-2.9905-1.606 0-2.548.7199-2.935 1.8275h-8.197c.72-4.8181 4.985-8.6393 11.409-8.6393 7.088 0 11.131 3.7659 11.131 10.2453zm-8.362-6.9779v-1.4399c-.554-1.0522-2.049-1.7167-3.655-1.7167-1.717 0-3.434.7199-3.434 2.3813 0 1.7168 1.717 2.4367 3.434 2.4367 1.606 0 3.101-.6645 3.655-1.6614zm27.996 6.9779v-1.994c-1.163 1.329-3.599 2.548-6.147 2.548-7.199 0-11.131-5.8151-11.131-13.0145s3.932-13.0143 11.131-13.0143c2.548 0 4.984 1.2184 6.147 2.5475v-13.0697h8.695v35.997zm0-9.1931v-6.5902c-.664-1.3291-2.159-2.326-3.821-2.326-2.99 0-4.763 2.4368-4.763 5.6488s1.773 5.5934 4.763 5.5934c1.717 0 3.157-.9415 3.821-2.326zm35.471-2.049h-3.101v11.2421h-8.806v-34.0033h15.285c7.31 0 12.35 4.1535 12.35 11.5744 0 5.1503-2.603 8.6947-6.757 10.2453l7.975 12.1836h-9.858zm-3.101-15.2849v8.1962h5.538c3.156 0 4.596-1.606 4.596-4.0981s-1.44-4.0981-4.596-4.0981zm36.957 17.8323h8.03c-.886 5.7597-5.206 9.2487-11.685 9.2487-7.643 0-12.682-5.2613-12.682-13.0145 0-7.6978 5.316-13.0143 12.515-13.0143 7.643 0 11.962 5.095 11.962 12.5159v2.1598h-16.115c.277 2.9905 1.827 4.5965 4.32 4.5965 1.772 0 3.156-.7753 3.655-2.4921zm-3.822-10.0237c-2.049 0-3.433 1.2737-3.987 3.5997h7.532c-.111-2.0491-1.385-3.5997-3.545-3.5997zm30.98 27.5234v-10.799c-1.163 1.329-3.6 2.548-6.147 2.548-7.2 0-11.132-5.9259-11.132-13.0145 0-7.144 3.932-13.0143 11.132-13.0143 2.547 0 4.984 1.2184 6.147 2.5475v-1.9937h8.695v33.726zm0-17.9981v-6.5902c-.665-1.3291-2.105-2.326-3.821-2.326-2.991 0-4.763 2.4368-4.763 5.6488s1.772 5.5934 4.763 5.5934c1.661 0 3.156-.9415 3.821-2.326zm36.789-15.7279v24.921h-8.695v-2.16c-1.329 1.551-3.821 2.714-6.646 2.714-5.482 0-8.75-3.5999-8.75-9.1379v-16.3371h8.64v14.288c0 2.1045.996 3.5997 3.212 3.5997 1.606 0 3.101-1.0522 3.544-2.769v-15.1187zm19.084 16.2263h8.03c-.886 5.7597-5.206 9.2487-11.685 9.2487-7.643 0-12.682-5.2613-12.682-13.0145 0-7.6978 5.316-13.0143 12.515-13.0143 7.643 0 11.963 5.095 11.963 12.5159v2.1598h-16.116c.277 2.9905 1.828 4.5965 4.32 4.5965 1.772 0 3.156-.7753 3.655-2.4921zm-3.822-10.0237c-2.049 0-3.433 1.2737-3.987 3.5997h7.532c-.111-2.0491-1.385-3.5997-3.545-3.5997zm13.428 11.0206h8.474c.387 1.3845 1.606 2.1598 3.156 2.1598 1.44 0 2.548-.5538 2.548-1.7168 0-.9414-.72-1.2737-1.939-1.5506l-4.873-.9969c-4.154-.886-6.867-2.8797-6.867-7.2547 0-5.3165 4.762-8.4178 10.633-8.4178 6.812 0 10.522 3.1567 11.297 8.0855h-8.03c-.277-1.0522-1.052-1.9937-3.046-1.9937-1.273 0-2.326.5538-2.326 1.6614 0 .7753.554 1.163 1.717 1.3845l4.929 1.163c4.541 1.0522 6.978 3.4335 6.978 7.4763 0 5.3168-4.818 8.2518-10.91 8.2518-6.369 0-10.965-2.88-11.741-8.2518zm27.538-.8861v-9.5807h-3.655v-6.7564h3.655v-6.8671h8.584v6.8671h5.205v6.7564h-5.205v8.307c0 1.9383.941 2.769 2.658 2.769.941 0 1.993-.2216 2.769-.5538v7.3654c-.997.443-2.88.775-4.818.775-5.871 0-9.193-2.769-9.193-9.0819z" id="error-description"/></svg>
127
+ </header>
128
+ <article>
129
+ <p><strong>The server cannot process the request due to a client error.</strong> Please check the request and try again. If you're the application owner check the logs for more information.</p>
130
+ </article>
131
+ </main>
132
+
133
+ </body>
134
+
135
+ </html>
data/public/404.html ADDED
@@ -0,0 +1,135 @@
1
+ <!doctype html>
2
+
3
+ <html lang="en">
4
+
5
+ <head>
6
+
7
+ <title>The page you were looking for doesn't exist (404 Not found)</title>
8
+
9
+ <meta charset="utf-8">
10
+ <meta name="viewport" content="initial-scale=1, width=device-width">
11
+ <meta name="robots" content="noindex, nofollow">
12
+
13
+ <style>
14
+
15
+ *, *::before, *::after {
16
+ box-sizing: border-box;
17
+ }
18
+
19
+ * {
20
+ margin: 0;
21
+ }
22
+
23
+ html {
24
+ font-size: 16px;
25
+ }
26
+
27
+ body {
28
+ background: #FFF;
29
+ color: #261B23;
30
+ display: grid;
31
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Aptos, Roboto, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
32
+ font-size: clamp(1rem, 2.5vw, 2rem);
33
+ -webkit-font-smoothing: antialiased;
34
+ font-style: normal;
35
+ font-weight: 400;
36
+ letter-spacing: -0.0025em;
37
+ line-height: 1.4;
38
+ min-height: 100dvh;
39
+ place-items: center;
40
+ text-rendering: optimizeLegibility;
41
+ -webkit-text-size-adjust: 100%;
42
+ }
43
+
44
+ #error-description {
45
+ fill: #d30001;
46
+ }
47
+
48
+ #error-id {
49
+ fill: #f0eff0;
50
+ }
51
+
52
+ @media (prefers-color-scheme: dark) {
53
+ body {
54
+ background: #101010;
55
+ color: #e0e0e0;
56
+ }
57
+
58
+ #error-description {
59
+ fill: #FF6161;
60
+ }
61
+
62
+ #error-id {
63
+ fill: #2c2c2c;
64
+ }
65
+ }
66
+
67
+ a {
68
+ color: inherit;
69
+ font-weight: 700;
70
+ text-decoration: underline;
71
+ text-underline-offset: 0.0925em;
72
+ }
73
+
74
+ b, strong {
75
+ font-weight: 700;
76
+ }
77
+
78
+ i, em {
79
+ font-style: italic;
80
+ }
81
+
82
+ main {
83
+ display: grid;
84
+ gap: 1em;
85
+ padding: 2em;
86
+ place-items: center;
87
+ text-align: center;
88
+ }
89
+
90
+ main header {
91
+ width: min(100%, 12em);
92
+ }
93
+
94
+ main header svg {
95
+ height: auto;
96
+ max-width: 100%;
97
+ width: 100%;
98
+ }
99
+
100
+ main article {
101
+ width: min(100%, 30em);
102
+ }
103
+
104
+ main article p {
105
+ font-size: 75%;
106
+ }
107
+
108
+ main article br {
109
+ display: none;
110
+
111
+ @media(min-width: 48em) {
112
+ display: inline;
113
+ }
114
+ }
115
+
116
+ </style>
117
+
118
+ </head>
119
+
120
+ <body>
121
+
122
+ <!-- This file lives in public/404.html -->
123
+
124
+ <main>
125
+ <header>
126
+ <svg height="172" viewBox="0 0 480 172" width="480" xmlns="http://www.w3.org/2000/svg"><path d="m124.48 3.00509-45.6889 100.02991h26.2239v-28.1168h38.119v28.1168h21.628v35.145h-21.628v30.82h-37.308v-30.82h-72.1833v-31.901l50.2851-103.27391zm115.583 168.69891c-40.822 0-64.884-35.146-64.884-85.7015 0-50.5554 24.062-85.700907 64.884-85.700907 40.823 0 64.884 35.145507 64.884 85.700907 0 50.5555-24.061 85.7015-64.884 85.7015zm0-133.2831c-17.572 0-22.709 21.8984-22.709 47.5816 0 25.6835 5.137 47.5815 22.709 47.5815 17.303 0 22.71-21.898 22.71-47.5815 0-25.6832-5.407-47.5816-22.71-47.5816zm165.328-35.41581-45.689 100.02991h26.224v-28.1168h38.119v28.1168h21.628v35.145h-21.628v30.82h-37.308v-30.82h-72.184v-31.901l50.285-103.27391z" id="error-id"/><path d="m157.758 68.9967v34.0033h-7.199l-14.233-19.8814v19.8814h-8.584v-34.0033h8.307l13.125 18.7184v-18.7184zm28.454 21.5428c0 7.6978-5.15 13.0145-12.737 13.0145-7.532 0-12.738-5.3167-12.738-13.0145s5.206-13.0143 12.738-13.0143c7.587 0 12.737 5.3165 12.737 13.0143zm-8.528 0c0-3.4336-1.496-5.8703-4.209-5.8703-2.659 0-4.154 2.4367-4.154 5.8703s1.495 5.8149 4.154 5.8149c2.713 0 4.209-2.3813 4.209-5.8149zm13.184 3.8766v-9.5807h-3.655v-6.7564h3.655v-6.8671h8.584v6.8671h5.205v6.7564h-5.205v8.307c0 1.9383.941 2.769 2.658 2.769.941 0 1.994-.2216 2.769-.5538v7.3654c-.997.443-2.88.775-4.818.775-5.87 0-9.193-2.769-9.193-9.0819zm37.027 8.5839h-8.806v-34.0033h23.924v7.6978h-15.118v6.7564h13.9v7.5316h-13.9zm41.876-12.4605c0 7.6978-5.15 13.0145-12.737 13.0145-7.532 0-12.738-5.3167-12.738-13.0145s5.206-13.0143 12.738-13.0143c7.587 0 12.737 5.3165 12.737 13.0143zm-8.529 0c0-3.4336-1.495-5.8703-4.208-5.8703-2.659 0-4.154 2.4367-4.154 5.8703s1.495 5.8149 4.154 5.8149c2.713 0 4.208-2.3813 4.208-5.8149zm35.337-12.4605v24.921h-8.695v-2.16c-1.329 1.551-3.821 2.714-6.646 2.714-5.482 0-8.75-3.5999-8.75-9.1379v-16.3371h8.64v14.288c0 2.1045.997 3.5997 3.212 3.5997 1.606 0 3.101-1.0522 3.544-2.769v-15.1187zm4.076 24.921v-24.921h8.694v2.1598c1.385-1.5506 3.822-2.7136 6.701-2.7136 5.538 0 8.806 3.5997 8.806 9.1377v16.3371h-8.639v-14.2327c0-2.049-1.053-3.5443-3.268-3.5443-1.717 0-3.156.9969-3.6 2.7136v15.0634zm44.113 0v-1.994c-1.163 1.329-3.6 2.548-6.147 2.548-7.2 0-11.132-5.8151-11.132-13.0145s3.932-13.0143 11.132-13.0143c2.547 0 4.984 1.2184 6.147 2.5475v-13.0697h8.695v35.997zm0-9.1931v-6.5902c-.665-1.3291-2.16-2.326-3.821-2.326-2.991 0-4.763 2.4368-4.763 5.6488s1.772 5.5934 4.763 5.5934c1.717 0 3.156-.9415 3.821-2.326z" id="error-description"/></svg>
127
+ </header>
128
+ <article>
129
+ <p><strong>The page you were looking for doesn't exist.</strong> You may have mistyped the address or the page may have moved. If you're the application owner check the logs for more information.</p>
130
+ </article>
131
+ </main>
132
+
133
+ </body>
134
+
135
+ </html>
@@ -0,0 +1,135 @@
1
+ <!doctype html>
2
+
3
+ <html lang="en">
4
+
5
+ <head>
6
+
7
+ <title>Your browser is not supported (406 Not Acceptable)</title>
8
+
9
+ <meta charset="utf-8">
10
+ <meta name="viewport" content="initial-scale=1, width=device-width">
11
+ <meta name="robots" content="noindex, nofollow">
12
+
13
+ <style>
14
+
15
+ *, *::before, *::after {
16
+ box-sizing: border-box;
17
+ }
18
+
19
+ * {
20
+ margin: 0;
21
+ }
22
+
23
+ html {
24
+ font-size: 16px;
25
+ }
26
+
27
+ body {
28
+ background: #FFF;
29
+ color: #261B23;
30
+ display: grid;
31
+ font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Aptos, Roboto, "Segoe UI", "Helvetica Neue", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
32
+ font-size: clamp(1rem, 2.5vw, 2rem);
33
+ -webkit-font-smoothing: antialiased;
34
+ font-style: normal;
35
+ font-weight: 400;
36
+ letter-spacing: -0.0025em;
37
+ line-height: 1.4;
38
+ min-height: 100dvh;
39
+ place-items: center;
40
+ text-rendering: optimizeLegibility;
41
+ -webkit-text-size-adjust: 100%;
42
+ }
43
+
44
+ #error-description {
45
+ fill: #d30001;
46
+ }
47
+
48
+ #error-id {
49
+ fill: #f0eff0;
50
+ }
51
+
52
+ @media (prefers-color-scheme: dark) {
53
+ body {
54
+ background: #101010;
55
+ color: #e0e0e0;
56
+ }
57
+
58
+ #error-description {
59
+ fill: #FF6161;
60
+ }
61
+
62
+ #error-id {
63
+ fill: #2c2c2c;
64
+ }
65
+ }
66
+
67
+ a {
68
+ color: inherit;
69
+ font-weight: 700;
70
+ text-decoration: underline;
71
+ text-underline-offset: 0.0925em;
72
+ }
73
+
74
+ b, strong {
75
+ font-weight: 700;
76
+ }
77
+
78
+ i, em {
79
+ font-style: italic;
80
+ }
81
+
82
+ main {
83
+ display: grid;
84
+ gap: 1em;
85
+ padding: 2em;
86
+ place-items: center;
87
+ text-align: center;
88
+ }
89
+
90
+ main header {
91
+ width: min(100%, 12em);
92
+ }
93
+
94
+ main header svg {
95
+ height: auto;
96
+ max-width: 100%;
97
+ width: 100%;
98
+ }
99
+
100
+ main article {
101
+ width: min(100%, 30em);
102
+ }
103
+
104
+ main article p {
105
+ font-size: 75%;
106
+ }
107
+
108
+ main article br {
109
+ display: none;
110
+
111
+ @media(min-width: 48em) {
112
+ display: inline;
113
+ }
114
+ }
115
+
116
+ </style>
117
+
118
+ </head>
119
+
120
+ <body>
121
+
122
+ <!-- This file lives in public/406-unsupported-browser.html -->
123
+
124
+ <main>
125
+ <header>
126
+ <svg height="172" viewBox="0 0 480 172" width="480" xmlns="http://www.w3.org/2000/svg"><path d="m124.48 3.00509-45.6889 100.02991h26.2239v-28.1168h38.119v28.1168h21.628v35.145h-21.628v30.82h-37.308v-30.82h-72.1833v-31.901l50.2851-103.27391zm115.583 168.69891c-40.822 0-64.884-35.146-64.884-85.7015 0-50.5554 24.062-85.700907 64.884-85.700907 40.823 0 64.884 35.145507 64.884 85.700907 0 50.5555-24.061 85.7015-64.884 85.7015zm0-133.2831c-17.572 0-22.709 21.8984-22.709 47.5816 0 25.6835 5.137 47.5815 22.709 47.5815 17.303 0 22.71-21.898 22.71-47.5815 0-25.6832-5.407-47.5816-22.71-47.5816zm202.906 9.7326h-41.093c-2.433-7.2994-7.84-12.4361-17.302-12.4361-16.221 0-25.413 17.5728-25.954 34.8752v1.3517c5.137-7.0291 16.221-12.4361 30.82-12.4361 33.524 0 54.881 24.0612 54.881 53.7998 0 33.253-23.791 58.396-61.64 58.396-21.628 0-39.741-10.003-50.825-27.576-9.733-14.599-13.788-32.442-13.788-54.3406 0-51.9072 24.331-89.485807 66.236-89.485807 32.712 0 53.258 18.654107 58.665 47.851907zm-82.727 66.2355c0 13.247 9.463 22.439 22.71 22.439 12.977 0 22.439-9.192 22.439-22.439 0-13.517-9.462-22.7091-22.439-22.7091-13.247 0-22.71 9.1921-22.71 22.7091z" id="error-id"/><path d="m100.761 68.9967v34.0033h-7.1991l-14.2326-19.8814v19.8814h-8.5839v-34.0033h8.307l13.125 18.7184v-18.7184zm28.454 21.5428c0 7.6978-5.15 13.0145-12.737 13.0145-7.532 0-12.738-5.3167-12.738-13.0145s5.206-13.0143 12.738-13.0143c7.587 0 12.737 5.3165 12.737 13.0143zm-8.529 0c0-3.4336-1.495-5.8703-4.208-5.8703-2.659 0-4.154 2.4367-4.154 5.8703s1.495 5.8149 4.154 5.8149c2.713 0 4.208-2.3813 4.208-5.8149zm13.185 3.8766v-9.5807h-3.655v-6.7564h3.655v-6.8671h8.584v6.8671h5.205v6.7564h-5.205v8.307c0 1.9383.941 2.769 2.658 2.769.941 0 1.994-.2216 2.769-.5538v7.3654c-.997.443-2.88.775-4.818.775-5.87 0-9.193-2.769-9.193-9.0819zm39.02-25.4194h9.083l12.958 34.0033h-9.027l-2.436-6.5902h-12.35l-2.381 6.5902h-8.806zm4.431 10.5222-3.489 9.5807h6.978zm17.44 11.0206c0-7.6978 5.095-13.0143 12.572-13.0143 6.701 0 10.854 3.9874 11.574 9.8023h-8.418c-.221-1.4953-1.384-2.6029-3.156-2.6029-2.437 0-3.988 2.2706-3.988 5.8149s1.551 5.7595 3.988 5.7595c1.772 0 2.935-1.0522 3.156-2.5475h8.418c-.72 5.7596-4.873 9.8025-11.574 9.8025-7.477 0-12.572-5.3167-12.572-13.0145zm25.676 0c0-7.6978 5.095-13.0143 12.572-13.0143 6.701 0 10.854 3.9874 11.574 9.8023h-8.418c-.221-1.4953-1.384-2.6029-3.156-2.6029-2.437 0-3.988 2.2706-3.988 5.8149s1.551 5.7595 3.988 5.7595c1.772 0 2.935-1.0522 3.156-2.5475h8.418c-.72 5.7596-4.873 9.8025-11.574 9.8025-7.477 0-12.572-5.3167-12.572-13.0145zm42.013 3.7658h8.031c-.887 5.7597-5.206 9.2487-11.686 9.2487-7.642 0-12.682-5.2613-12.682-13.0145 0-7.6978 5.317-13.0143 12.516-13.0143 7.643 0 11.962 5.095 11.962 12.5159v2.1598h-16.115c.277 2.9905 1.827 4.5965 4.319 4.5965 1.773 0 3.157-.7753 3.655-2.4921zm-3.821-10.0237c-2.049 0-3.433 1.2737-3.987 3.5997h7.532c-.111-2.0491-1.385-3.5997-3.545-3.5997zm23.4 16.7244v10.799h-8.694v-33.726h8.694v1.9937c1.163-1.3291 3.6-2.5475 6.148-2.5475 7.199 0 11.131 5.8703 11.131 13.0143 0 7.0886-3.932 13.0145-11.131 13.0145-2.548 0-4.985-1.219-6.148-2.548zm0-13.7893v6.5902c.665 1.3845 2.16 2.326 3.822 2.326 2.99 0 4.762-2.3814 4.762-5.5934s-1.772-5.6488-4.762-5.6488c-1.717 0-3.157.9969-3.822 2.326zm21.892 7.1994v-9.5807h-3.655v-6.7564h3.655v-6.8671h8.584v6.8671h5.206v6.7564h-5.206v8.307c0 1.9383.941 2.769 2.658 2.769.942 0 1.994-.2216 2.769-.5538v7.3654c-.997.443-2.88.775-4.818.775-5.87 0-9.193-2.769-9.193-9.0819zm39.458 8.5839h-8.363v-1.274c-.83.831-3.322 1.717-5.981 1.717-4.928 0-9.082-2.769-9.082-8.0301 0-4.818 4.154-7.9193 9.581-7.9193 2.049 0 4.486.6646 5.482 1.3845v-1.606c0-1.606-.941-2.9905-3.045-2.9905-1.606 0-2.548.7199-2.936 1.8275h-8.196c.72-4.8181 4.984-8.6393 11.408-8.6393 7.089 0 11.132 3.7659 11.132 10.2453zm-8.363-6.9779v-1.4399c-.553-1.0522-2.049-1.7167-3.655-1.7167-1.716 0-3.433.7199-3.433 2.3813 0 1.7168 1.717 2.4367 3.433 2.4367 1.606 0 3.102-.6645 3.655-1.6614zm20.742 4.9839v1.994h-8.694v-35.997h8.694v13.0697c1.163-1.3291 3.6-2.5475 6.148-2.5475 7.199 0 11.131 5.8149 11.131 13.0143s-3.932 13.0145-11.131 13.0145c-2.548 0-4.985-1.219-6.148-2.548zm0-13.7893v6.5902c.665 1.3845 2.105 2.326 3.822 2.326 2.99 0 4.762-2.3814 4.762-5.5934s-1.772-5.6488-4.762-5.6488c-1.662 0-3.157.9969-3.822 2.326zm28.759-20.2137v35.997h-8.695v-35.997zm19.172 27.3023h8.03c-.886 5.7597-5.206 9.2487-11.685 9.2487-7.643 0-12.682-5.2613-12.682-13.0145 0-7.6978 5.316-13.0143 12.516-13.0143 7.642 0 11.962 5.095 11.962 12.5159v2.1598h-16.116c.277 2.9905 1.828 4.5965 4.32 4.5965 1.772 0 3.157-.7753 3.655-2.4921zm-3.821-10.0237c-2.049 0-3.434 1.2737-3.988 3.5997h7.532c-.111-2.0491-1.384-3.5997-3.544-3.5997z" id="error-description"/></svg>
127
+ </header>
128
+ <article>
129
+ <p><strong>Your browser is not supported.</strong><br> Please upgrade your browser to continue.</p>
130
+ </article>
131
+ </main>
132
+
133
+ </body>
134
+
135
+ </html>