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
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ jobs:
- run: python -m unittest discover -s tests -v
working-directory: dashboard
- name: open-access + markup contract tests
run: node --test tests/domains_markup.test.mjs tests/open_access.test.mjs tests/notes_markup.test.mjs tests/review_pr122_drawer.test.mjs tests/flux_markup.test.mjs tests/review_pr125.test.mjs tests/criteria_markup.test.mjs tests/review_pr127_drawer.test.mjs tests/phone_layout.test.mjs
run: node --test tests/domains_markup.test.mjs tests/open_access.test.mjs tests/notes_markup.test.mjs tests/review_pr122_drawer.test.mjs tests/flux_markup.test.mjs tests/review_pr125.test.mjs tests/criteria_markup.test.mjs tests/review_pr127_drawer.test.mjs tests/phone_layout.test.mjs tests/wordmark.test.mjs
working-directory: dashboard

schema-check:
Expand Down
14 changes: 7 additions & 7 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 7 additions & 7 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ members = [
resolver = "2"

[workspace.package]
version = "3.51.4"
version = "3.51.5"
edition = "2024"
license-file = "LICENSE"
authors = ["PureTensor, Inc. <hal@puretensor.ai>"]
Expand Down Expand Up @@ -52,12 +52,12 @@ rmcp = { version = "3.3.0", features = ["server", "macros", "schemars", "transpo
futures-util = { version = "0.3", default-features = false }

# Internal crates
ptask-core = { path = "crates/ptask-core", version = "3.51.4" }
ptask-tui = { path = "crates/ptask-tui", version = "3.51.4" }
ptask-server = { path = "crates/ptask-server", version = "3.51.4" }
ptask-bot = { path = "crates/ptask-bot", version = "3.51.4" }
ptask-distill = { path = "crates/ptask-distill", version = "3.51.4" }
ptask-notify = { path = "crates/ptask-notify", version = "3.51.4" }
ptask-core = { path = "crates/ptask-core", version = "3.51.5" }
ptask-tui = { path = "crates/ptask-tui", version = "3.51.5" }
ptask-server = { path = "crates/ptask-server", version = "3.51.5" }
ptask-bot = { path = "crates/ptask-bot", version = "3.51.5" }
ptask-distill = { path = "crates/ptask-distill", version = "3.51.5" }
ptask-notify = { path = "crates/ptask-notify", version = "3.51.5" }

# HMAC for outbound webhook signing (v0.3.5).
sha2 = "0.10"
Expand Down
4 changes: 2 additions & 2 deletions crates/ptask-core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ pub struct DashConfig {
/// host of `$PTASK_DASH_URL`, and this machine's own short hostname.
/// Lower-cased, without port or trailing dot.
pub allowed_hosts: Vec<String>,
/// Brand shown in the cockpit (`$PTASK_DASH_TITLE`, default "PTASK").
/// Brand shown in the cockpit (`$PTASK_DASH_TITLE`, default "pTASK").
pub title: String,
/// Domain hats (`$PTASK_DASH_DOMAINS`). Empty = legacy ENG/MGMT mode.
pub domains: Vec<DashDomain>,
Expand Down Expand Up @@ -286,7 +286,7 @@ impl Config {
frame_ancestor: env_nonempty("PTASK_DASH_FRAME_ANCESTOR"),
url: env_nonempty("PTASK_DASH_URL"),
allowed_hosts,
title: env_nonempty("PTASK_DASH_TITLE").unwrap_or_else(|| "PTASK".into()),
title: env_nonempty("PTASK_DASH_TITLE").unwrap_or_else(|| "pTASK".into()),
domains,
default_domain,
},
Expand Down
6 changes: 6 additions & 0 deletions dashboard/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,12 @@ The canonical `pt serve` and `tasks.db` are never modified — nothing to revert

## Version

- **v0.26.2** (pt 3.51.5) — The brand is now **pTASK**, styled like pCIRCUIT
and pNOC: a white lowercase "p", then the name in capitals in the shared
wordmark blue (#40c4ff). Covers the header, the page title and the
home-screen app name. `PTASK_DASH_TITLE` (sidecar and `pt serve`) now
defaults to `pTASK`; a configured brand in the same "p" + capitals form gets
the same treatment, and any other brand stays plain text.
- **v0.26.1** (pt 3.51.4) — iPhone 18 Pro Max home-screen app fit, checked in
the iOS 27 simulator (440×956, 62px status-bar inset). A cold launch no
longer leaves the board under a doubled 124px gap (iOS parks the page at
Expand Down
6 changes: 3 additions & 3 deletions dashboard/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
PTASK_DB SQLite path (default ~/puretensor-tasks/tasks.db)
PTASK_BIN pt binary (default ~/.cargo/bin/pt)
PTASK_DASH_BIND bind addr (default 127.0.0.1:9510)
PTASK_DASH_TITLE dashboard brand (default "PTASK")
PTASK_DASH_TITLE dashboard brand (default "pTASK")
PTASK_DASH_DOMAINS comma-separated key[:Label[:ABBR]] domain list
PTASK_DASH_DEFAULT_DOMAIN configured key used for unlabelled tasks
PTASK_DASH_WWW static dir (default ./www next to this file)
Expand Down Expand Up @@ -147,7 +147,7 @@ def resolve_default_domain(domains: list[dict], requested: str | None) -> str |
# the dashboard exposes the same task data. Production sets PTASK_DASH_BIND.
BIND = os.environ.get("PTASK_DASH_BIND", "127.0.0.1:9510")

VERSION = "0.26.1"
VERSION = "0.26.2"


def _allowed_host_entry(entry: str) -> str:
Expand All @@ -172,7 +172,7 @@ def _allowed_host_entry(entry: str) -> str:
# or aws child inherits it.
DECIDE_TOKEN_MIN = 16
DECIDE_TOKEN = os.environ.pop("PTASK_DASH_DECIDE_TOKEN", "").strip()
DASH_TITLE = os.environ.get("PTASK_DASH_TITLE", "PTASK")
DASH_TITLE = os.environ.get("PTASK_DASH_TITLE", "pTASK")
DASH_DOMAINS = parse_domains(os.environ.get("PTASK_DASH_DOMAINS"))
DASH_DEFAULT_DOMAIN = resolve_default_domain(
DASH_DOMAINS, os.environ.get("PTASK_DASH_DEFAULT_DOMAIN"),
Expand Down
62 changes: 62 additions & 0 deletions dashboard/tests/wordmark.test.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// pTASK wordmark (dashboard 0.26.2): the brand reads like pCIRCUIT and pNOC,
// a white lowercase "p" then the name in capitals in the wordmark blue. Runs
// the shipped renderBrand against a fake element, and pins the markup and CSS.

import test from "node:test";
import assert from "node:assert/strict";
import { readFileSync } from "node:fs";

const shell = readFileSync(new URL("../www/index.html", import.meta.url), "utf8");

const src = shell.match(/\nfunction renderBrand\(el,title\)\{[\s\S]*?\n\}\n/);
assert.ok(src, "renderBrand is in index.html");

function render(title) {
const doc = { createElement: () => ({ className: "", textContent: "" }) };
const el = {
textContent: "",
children: null,
replaceChildren(...nodes) { this.children = nodes; this.textContent = ""; },
};
new Function("document", `${src[0]}; return renderBrand;`)(doc)(el, title);
return el;
}

test("pTASK renders as a plain p and a blue TASK", () => {
const el = render("pTASK");
assert.equal(el.children.length, 2);
assert.equal(el.children[0], "p");
assert.equal(el.children[1].className, "wordmark-name");
assert.equal(el.children[1].textContent, "TASK");
});

test("another tenant's brand stays plain text", () => {
for (const title of ["ALAN", "PTASK", "pt", "pure"]) {
const el = render(title);
assert.equal(el.children, null, title);
assert.equal(el.textContent, title);
}
});

test("the shell ships the wordmark before config arrives, and defaults to pTASK", () => {
assert.match(shell, /<b id="brandTitle">p<span class="wordmark-name">TASK<\/span><\/b>/);
assert.match(shell, /cfg\.title:'pTASK'/);
assert.match(shell, /<meta name="apple-mobile-web-app-title" content="pTASK">/);
assert.match(shell, /<title>pTASK · Triage Cockpit<\/title>/);
});

test("the name is in the shared wordmark blue, the p in white", () => {
assert.match(shell, /--wordmark:#40c4ff;/);
assert.match(shell, /\.brandtxt b\{[^}]*color:#fff[^}]*\}/);
assert.match(shell, /\.brandtxt b \.wordmark-name\{color:var\(--wordmark\)\}/);
});

test("the wordmark is in pCIRCUIT's system sans, not the mission theme's mono", () => {
assert.match(shell, /--font-wordmark:-apple-system,BlinkMacSystemFont,"SF Pro Text"/);
assert.match(shell, /\.brandtxt b\{font-family:var\(--font-wordmark\)/);
});

test("the manifest names the home-screen app pTASK", () => {
const manifest = JSON.parse(readFileSync(new URL("../www/manifest.webmanifest", import.meta.url), "utf8"));
assert.equal(manifest.short_name, "pTASK");
});
31 changes: 25 additions & 6 deletions dashboard/www/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="apple-mobile-web-app-title" content="PTASK">
<meta name="apple-mobile-web-app-title" content="pTASK">
<link rel="apple-touch-icon" href="/apple-touch-icon.png">
<link rel="manifest" href="/manifest.webmanifest">
<title>PTASK · Triage Cockpit</title>
<title>pTASK · Triage Cockpit</title>
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgMTAwIDEwMCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48ZGVmcz48bGluZWFyR3JhZGllbnQgaWQ9InB0ZyIgeDE9IjAlIiB5MT0iMCUiIHgyPSIxMDAlIiB5Mj0iMTAwJSI+PHN0b3Agb2Zmc2V0PSIwJSIgc3RvcC1jb2xvcj0iIzAwRDRBQSIvPjxzdG9wIG9mZnNldD0iMTAwJSIgc3RvcC1jb2xvcj0iIzAwODBGRiIvPjwvbGluZWFyR3JhZGllbnQ+PC9kZWZzPjxyZWN0IHg9IjIiIHk9IjIiIHdpZHRoPSI5NiIgaGVpZ2h0PSI5NiIgcng9IjIyIiBmaWxsPSIjMGQxNjIyIiBzdHJva2U9IiMxZDJjM2QiIHN0cm9rZS13aWR0aD0iMiIvPjxwYXRoIGQ9Ik0yMCAyNCBIODAgTDU3IDU0IFY3OCBMNDMgNzAgVjU0IFoiIGZpbGw9Im5vbmUiIHN0cm9rZT0idXJsKCNwdGcpIiBzdHJva2Utd2lkdGg9IjUuNSIgc3Ryb2tlLWxpbmVqb2luPSJyb3VuZCIvPjxjaXJjbGUgY3g9IjUwIiBjeT0iMjQiIHI9IjAiIGZpbGw9InVybCgjcHRnKSIvPjwvc3ZnPg==">
<style>
/* ===================================================================== THEME
Expand All @@ -22,6 +22,9 @@
:root{
--gap:14px; --radius:14px; --speed:.45s;
--teal:#00D4AA; --blue:#0080FF;
/* Wordmark blue shared with pCIRCUIT and pNOC: "p" white, name in this. */
--wordmark:#40c4ff;
--font-wordmark:-apple-system,BlinkMacSystemFont,"SF Pro Text","Inter","Segoe UI",Roboto,sans-serif;
--p5:#ff3b5c; --p4:#ff9f43; --p3:#ffd93d; --p2:#4dabf7; --p1:#8a8aa8;
/* ink on saturated fills (badges, gradient buttons) — dark passes >=4.5 on
every priority fill and both gradient ends; white never did on p1/p2/teal */
Expand Down Expand Up @@ -79,6 +82,7 @@
--accent:#ff9f43; --accent2:#cc88ff;
--p5:#ff5544; --p4:#ff9f43; --p3:#ffcc66; --p2:#99ccff; --p1:#cc99cc;
--font:'Antonio','Arial Narrow',sans-serif; --font-head:'Antonio','Arial Narrow',sans-serif;
--font-wordmark:var(--font-head);
--shadow:none; --card-bg:#15151c;
--glow:none; --chip-radius:0 14px 14px 0;
--header-bg:#000; --grad:linear-gradient(90deg,#ff9f43,#cc88ff);
Expand Down Expand Up @@ -144,7 +148,10 @@
.brand{display:flex;align-items:center;gap:12px}
.cube{width:34px;height:34px;flex:none;filter:drop-shadow(0 0 8px rgba(0,212,170,.5))}
.brandtxt{display:flex;flex-direction:column;line-height:1.05}
.brandtxt b{font-family:var(--font-head);font-size:18px;letter-spacing:.14em;color:#fff;font-weight:800}
/* Product wordmark, matching pCIRCUIT and pNOC: white lowercase "p", the name
in capitals in the wordmark blue (see renderBrand). */
.brandtxt b{font-family:var(--font-wordmark);font-size:18px;letter-spacing:.06em;color:#fff;font-weight:700}
.brandtxt b .wordmark-name{color:var(--wordmark)}
.brandtxt small{font-size:10px;letter-spacing:.3em;color:var(--teal);text-transform:uppercase}
.accentline{height:3px;background:var(--dgrad);width:100%;transition:background var(--speed)}

Expand Down Expand Up @@ -499,6 +506,7 @@
[data-theme="lcars"] .chip{border-radius:0 14px 14px 0;border:none;background:#1d1d28}
[data-theme="lcars"] .statusbar{border:none;border-radius:8px 24px 24px 8px;background:#0d0d12;box-shadow:inset 14px 0 0 #cc88ff;padding-left:26px}
[data-theme="lcars"] .brandtxt b{color:#ff9f43}
[data-theme="lcars"] .brandtxt b .wordmark-name{color:inherit}
/* costume off below 700px — the 74px rail + 118px indent ate a third of a
phone screen and forced horizontal scroll at 320px */
@media(max-width:700px){
Expand Down Expand Up @@ -959,7 +967,7 @@
<div class="hdr">
<div class="brand">
<svg class="cube" viewBox="0 0 100 100" aria-hidden="true"><defs><linearGradient id="ptg" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#00D4AA"/><stop offset="100%" stop-color="#0080FF"/></linearGradient></defs><path d="M20 24 H80 L57 54 V78 L43 70 V54 Z" fill="none" stroke="url(#ptg)" stroke-width="5.5" stroke-linejoin="round"/></svg>
<div class="brandtxt"><b id="brandTitle">PTASK</b><small>Intelligence Distilled</small></div>
<div class="brandtxt"><b id="brandTitle">p<span class="wordmark-name">TASK</span></b><small>Intelligence Distilled</small></div>
</div>
<span class="clock" id="clock">--:--:-- UTC</span>
<div class="spacer"></div>
Expand Down Expand Up @@ -1184,6 +1192,17 @@ <h3 id="compose-h">New task</h3>
const item=_domainByKey.get(d);
return `var(--domain-${item?item.palette:0}-text)`;
}
/* A "p"-family brand (pTASK, like pNOC and pCIRCUIT) is a white lowercase p
and the rest of the name in the wordmark blue. Any other configured brand
(another tenant's PTASK_DASH_TITLE) renders as plain text. */
function renderBrand(el,title){
const m=/^p([A-Z0-9].*)$/.exec(title);
if(!m){el.textContent=title;return}
const name=document.createElement('span');
name.className='wordmark-name';
name.textContent=m[1];
el.replaceChildren('p',name);
}
function applyDomainConfig(cfg){
const configured=Array.isArray(cfg&&cfg.domains)&&cfg.domains.length>0;
const source=configured?cfg.domains:LEGACY_DOMAINS;
Expand All @@ -1197,8 +1216,8 @@ <h3 id="compose-h">New task</h3>
CDOM_OPTS=[['auto','AUTO','var(--muted)'],
..._domains.map(d=>[d.key,d.abbr,domainColor(d)])];

const title=String(cfg&&cfg.title!=null?cfg.title:'PTASK');
$('#brandTitle').textContent=title;
const title=String(cfg&&cfg.title!=null?cfg.title:'pTASK');
renderBrand($('#brandTitle'),title);
document.title=title+' · Triage Cockpit';
const appTitle=$('meta[name="apple-mobile-web-app-title"]');
if(appTitle) appTitle.setAttribute('content',title);
Expand Down
4 changes: 2 additions & 2 deletions dashboard/www/manifest.webmanifest
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "PTASK Triage Cockpit",
"short_name": "PTASK",
"name": "pTASK Triage Cockpit",
"short_name": "pTASK",
"description": "PureTensor sovereign task triage",
"start_url": "/",
"display": "standalone",
Expand Down
4 changes: 2 additions & 2 deletions docs/gen/pt.1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.ie \n(.g .ds Aq \(aq
.el .ds Aq '
.TH pt 1 "pt 3.51.4"
.TH pt 1 "pt 3.51.5"
.SH NAME
pt \- Sovereign task manager for PureTensor
.SH SYNOPSIS
Expand Down Expand Up @@ -208,4 +208,4 @@ Generate shell completions (bash/zsh/fish) to stdout
pt\-help(1)
Print this message or the help of the given subcommand(s)
.SH VERSION
v3.51.4
v3.51.5
Loading