@papi-ai/server 0.7.41 → 0.7.43
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.
|
@@ -82,7 +82,12 @@ Your output is **not done** if ANY of these is true (these are falsifiable — c
|
|
|
82
82
|
- [ ] Gradient text or gradient fill used decoratively (the generic-AI look).
|
|
83
83
|
- [ ] Your brand accent used as a glow / dark-mode-only sheen instead of solid, intentional colour.
|
|
84
84
|
- [ ] An "earned" signal colour (insight/intelligence/premium) used as a plain decorative fill.
|
|
85
|
-
- [ ]
|
|
85
|
+
- [ ] Two elements competing for dominance (both fight for the eye). NOTE: a page with NO hero is
|
|
86
|
+
fine when nothing must lead — do not manufacture one to satisfy this line; only *competing*
|
|
87
|
+
dominance fails (see The core principle).
|
|
88
|
+
- [ ] Guidance, state, or a next action explained in a sentence of helper text where a visual cue
|
|
89
|
+
(position, size, colour, icon, a signpost, motion-on-change) would carry it — prose used as a
|
|
90
|
+
crutch for missing visual steering.
|
|
86
91
|
- [ ] More than ~3 sections fully visible above the fold.
|
|
87
92
|
- [ ] Identical-sized cards in a uniform row (flat hierarchy — needs a dominant 2×+ cell).
|
|
88
93
|
- [ ] Monospace on labels, status, timestamps, or nav.
|
|
@@ -121,6 +126,16 @@ Return a tight report (this is data, not prose):
|
|
|
121
126
|
|
|
122
127
|
## The core principle
|
|
123
128
|
|
|
124
|
-
**Composition > decoration.** A page with perfect tokens and flat hierarchy is
|
|
125
|
-
slightly-off tokens and a clear
|
|
126
|
-
|
|
129
|
+
**Composition > decoration, and show > tell.** A page with perfect tokens and flat hierarchy is
|
|
130
|
+
worse than one with slightly-off tokens and a clear reading order where every element earns its
|
|
131
|
+
space. Two rules generalist agents keep getting wrong:
|
|
132
|
+
|
|
133
|
+
- **Steer with visuals, not text.** When the user needs guidance — what to do, where to look, what
|
|
134
|
+
state something is in — reach for a VISUAL cue first: position, size, colour, an icon, a
|
|
135
|
+
connecting line, a spatial signpost, motion on change. A sentence of helper text is the last
|
|
136
|
+
resort, not the first. Over-explaining in prose is the default AI failure mode; a well-placed
|
|
137
|
+
arrow, a pulse, or a bolded number beats a paragraph. Visual steering and motion beat words.
|
|
138
|
+
- **A hero is conditional, not mandatory.** Give the page one dominant focal point WHEN it has a
|
|
139
|
+
single thing that must lead. Dense tool, list, board, and settings surfaces can carry a calm, even
|
|
140
|
+
hierarchy — do not manufacture a hero, an oversized stat, or a promoted banner where the content
|
|
141
|
+
has no natural lead. Only *competing* dominance is always wrong; the absence of a hero is not.
|
|
@@ -48,15 +48,17 @@ Plus a one-line page read: `kind / audience / the one thing they must see first`
|
|
|
48
48
|
3. **Read the target page in full** — not just the component you're editing. You need full page
|
|
49
49
|
context to judge compositional hierarchy.
|
|
50
50
|
4. **List all sibling components** on the page. You'll weigh each one's visual weight against the others.
|
|
51
|
-
5. **Check both states:** populated and empty/zero-data. Both need a hero
|
|
51
|
+
5. **Check both states:** populated and empty/zero-data. Both need clear hierarchy (a hero only where one is warranted — see Check 1).
|
|
52
52
|
|
|
53
53
|
## Step 2: The Seven Checks
|
|
54
54
|
|
|
55
55
|
For each, give ✅ Pass / ⚠️ Weak / ❌ Fail plus a one-line reason.
|
|
56
56
|
|
|
57
|
-
### Check 1: Hero Element
|
|
58
|
-
>
|
|
59
|
-
|
|
57
|
+
### Check 1: Hero Element (conditional — NOT every page needs one)
|
|
58
|
+
> Give the page one dominant element WHEN it has one thing that must lead. A hero is not mandatory.
|
|
59
|
+
Does this page have a single thing that must lead? If yes: name it; missing/weak = ⚠️/❌. If no (a
|
|
60
|
+
dense tool / list / board / settings surface): a calm, even hierarchy is ✅ — do NOT manufacture a
|
|
61
|
+
hero to pass this check. Two elements *competing* for dominance is ALWAYS ❌ (the real failure).
|
|
60
62
|
|
|
61
63
|
### Check 2: Reading Order
|
|
62
64
|
> hero → primary action → supporting content → tertiary.
|
|
@@ -101,7 +103,11 @@ Run through every named anti-pattern and flag matches. Common universal ones:
|
|
|
101
103
|
- Gradient text or gradient fill used decoratively.
|
|
102
104
|
- Brand accent as a glow / dark-only sheen instead of solid intentional colour.
|
|
103
105
|
- A "signal" colour used as a plain decorative fill.
|
|
104
|
-
-
|
|
106
|
+
- Two elements competing for dominance (both fight for the eye). NOT a fail: a page with no hero
|
|
107
|
+
when nothing must lead (see Check 1) — only *competing* dominance fails here.
|
|
108
|
+
- Guidance, state, or a next action carried by a sentence of helper text where a visual cue
|
|
109
|
+
(position, size, colour, an icon, a signpost, motion-on-change) would do — prose as a crutch for
|
|
110
|
+
missing visual steering. Prefer showing over telling.
|
|
105
111
|
- Identical-sized cards in a uniform row (flat hierarchy).
|
|
106
112
|
- Monospace on labels / status / timestamps / nav.
|
|
107
113
|
- Header, label, and value at the same size+weight.
|
|
@@ -158,5 +164,10 @@ The pre-build critique catches composition; this catches what's only visible in
|
|
|
158
164
|
|
|
159
165
|
## The Core Principle
|
|
160
166
|
|
|
161
|
-
**Composition > Decoration.** A page with perfect tokens and flat hierarchy is
|
|
162
|
-
slightly-off tokens and clear hierarchy.
|
|
167
|
+
**Composition > Decoration, and show > tell.** A page with perfect tokens and flat hierarchy is
|
|
168
|
+
worse than one with slightly-off tokens and clear hierarchy. Two things generalist agents keep
|
|
169
|
+
getting wrong: (1) **steer with visuals, not text** — reach for position, size, colour, an icon, a
|
|
170
|
+
signpost, or motion-on-change before a sentence of helper text; over-explaining in prose is the
|
|
171
|
+
default AI failure mode. (2) **A hero is conditional** — give a page one dominant element only when
|
|
172
|
+
it has one thing that must lead; dense list / tool / settings surfaces carry a calm, even hierarchy,
|
|
173
|
+
so do not manufacture a hero. Clear reading order, everything earns its space, show before you tell.
|
|
@@ -73,7 +73,7 @@ __export(git_exports, {
|
|
|
73
73
|
taskBranchName: () => taskBranchName,
|
|
74
74
|
withBaseBranchSync: () => withBaseBranchSync
|
|
75
75
|
});
|
|
76
|
-
import { execFileSync } from "child_process";
|
|
76
|
+
import { execFileSync, spawnSync } from "child_process";
|
|
77
77
|
function isGitAvailable() {
|
|
78
78
|
try {
|
|
79
79
|
execFileSync("git", ["--version"], { stdio: "ignore" });
|
|
@@ -317,21 +317,24 @@ function gitPull(cwd) {
|
|
|
317
317
|
}
|
|
318
318
|
}
|
|
319
319
|
function gitPush(cwd, branch) {
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
const isTimeout = msg.includes("ETIMEDOUT") || msg.includes("killed");
|
|
330
|
-
return {
|
|
331
|
-
success: false,
|
|
332
|
-
message: isTimeout ? `Push timed out after 30s.` : `Push failed: ${msg}`
|
|
333
|
-
};
|
|
320
|
+
const result = spawnSync("git", ["push", "-u", "origin", branch], {
|
|
321
|
+
cwd,
|
|
322
|
+
encoding: "utf-8",
|
|
323
|
+
timeout: GIT_NETWORK_TIMEOUT_MS
|
|
324
|
+
});
|
|
325
|
+
if (result.error) {
|
|
326
|
+
const msg = result.error.message;
|
|
327
|
+
const isTimeout = msg.includes("ETIMEDOUT") || result.signal === "SIGTERM" || msg.includes("killed");
|
|
328
|
+
return { success: false, pushed: false, message: isTimeout ? "Push timed out after 30s." : `Push failed: ${msg}` };
|
|
334
329
|
}
|
|
330
|
+
const output = `${result.stdout ?? ""}${result.stderr ?? ""}`.trim();
|
|
331
|
+
if (result.status !== 0) {
|
|
332
|
+
return { success: false, pushed: false, message: `Push failed: ${output || `git exited ${result.status}`}` };
|
|
333
|
+
}
|
|
334
|
+
if (/Everything up-to-date/i.test(output)) {
|
|
335
|
+
return { success: true, pushed: false, message: `'${branch}' already up to date on origin \u2014 nothing to push.` };
|
|
336
|
+
}
|
|
337
|
+
return { success: true, pushed: true, message: `Pushed '${branch}' to origin.` };
|
|
335
338
|
}
|
|
336
339
|
function isGhAvailable() {
|
|
337
340
|
try {
|
|
@@ -1012,6 +1015,48 @@ var init_git = __esm({
|
|
|
1012
1015
|
}
|
|
1013
1016
|
});
|
|
1014
1017
|
|
|
1018
|
+
// src/lib/install-id.ts
|
|
1019
|
+
import { randomUUID as randomUUID7 } from "crypto";
|
|
1020
|
+
import { mkdirSync, readFileSync, writeFileSync, chmodSync } from "fs";
|
|
1021
|
+
import { homedir } from "os";
|
|
1022
|
+
import { join as join2 } from "path";
|
|
1023
|
+
var PAPI_HOME_DIR, INSTALL_ID_FILE;
|
|
1024
|
+
var init_install_id = __esm({
|
|
1025
|
+
"src/lib/install-id.ts"() {
|
|
1026
|
+
"use strict";
|
|
1027
|
+
PAPI_HOME_DIR = join2(homedir(), ".papi");
|
|
1028
|
+
INSTALL_ID_FILE = join2(PAPI_HOME_DIR, "install-id.json");
|
|
1029
|
+
}
|
|
1030
|
+
});
|
|
1031
|
+
|
|
1032
|
+
// src/lib/telemetry.ts
|
|
1033
|
+
function reportTelemetryEmitFailure(reason, ctx) {
|
|
1034
|
+
consecutiveTelemetryFailures += 1;
|
|
1035
|
+
console.error(
|
|
1036
|
+
`[telemetry] emit failed (${reason}) tool=${ctx.toolName} event=${ctx.eventType} project=${ctx.projectId}`
|
|
1037
|
+
);
|
|
1038
|
+
if (consecutiveTelemetryFailures >= TELEMETRY_BLACKOUT_THRESHOLD) {
|
|
1039
|
+
console.error(
|
|
1040
|
+
`[telemetry] BLACKOUT: ${consecutiveTelemetryFailures} consecutive telemetry emit failures \u2014 activation metrics are under-counting for this pod. Check the data-proxy /telemetry path (auth/RLS/network/schema).`
|
|
1041
|
+
);
|
|
1042
|
+
}
|
|
1043
|
+
}
|
|
1044
|
+
function noteTelemetryEmitSuccess() {
|
|
1045
|
+
consecutiveTelemetryFailures = 0;
|
|
1046
|
+
}
|
|
1047
|
+
var HOSTED_SUPABASE_URL, DEFAULT_TELEMETRY_ENDPOINT, MD_PINGS_SUPABASE_URL, consecutiveTelemetryFailures, TELEMETRY_BLACKOUT_THRESHOLD;
|
|
1048
|
+
var init_telemetry = __esm({
|
|
1049
|
+
"src/lib/telemetry.ts"() {
|
|
1050
|
+
"use strict";
|
|
1051
|
+
init_install_id();
|
|
1052
|
+
HOSTED_SUPABASE_URL = process.env["PAPI_HOSTED_SUPABASE_URL"] ?? "https://guewgygcpcmrcoppihzx.supabase.co";
|
|
1053
|
+
DEFAULT_TELEMETRY_ENDPOINT = `${HOSTED_SUPABASE_URL}/functions/v1/data-proxy`;
|
|
1054
|
+
MD_PINGS_SUPABASE_URL = process.env["PAPI_MD_PINGS_URL"] ?? HOSTED_SUPABASE_URL;
|
|
1055
|
+
consecutiveTelemetryFailures = 0;
|
|
1056
|
+
TELEMETRY_BLACKOUT_THRESHOLD = 3;
|
|
1057
|
+
}
|
|
1058
|
+
});
|
|
1059
|
+
|
|
1015
1060
|
// src/proxy-adapter.ts
|
|
1016
1061
|
var proxy_adapter_exports = {};
|
|
1017
1062
|
__export(proxy_adapter_exports, {
|
|
@@ -1058,6 +1103,7 @@ var JSONB_PASSTHROUGH_KEYS, DISPLAY_ID_METHODS, ProxyPapiAdapter;
|
|
|
1058
1103
|
var init_proxy_adapter = __esm({
|
|
1059
1104
|
"src/proxy-adapter.ts"() {
|
|
1060
1105
|
"use strict";
|
|
1106
|
+
init_telemetry();
|
|
1061
1107
|
JSONB_PASSTHROUGH_KEYS = /* @__PURE__ */ new Set([
|
|
1062
1108
|
"buildHandoff",
|
|
1063
1109
|
"stateHistory",
|
|
@@ -1420,6 +1466,7 @@ Check PAPI_PROJECT_ID in your .mcp.json config. Find your project ID in the PAPI
|
|
|
1420
1466
|
* telemetry failure must never surface as a tool error.
|
|
1421
1467
|
*/
|
|
1422
1468
|
emitTelemetry(event) {
|
|
1469
|
+
const ctx = { projectId: event.projectId, toolName: event.toolName, eventType: event.eventType };
|
|
1423
1470
|
fetch(`${this.endpoint}/telemetry`, {
|
|
1424
1471
|
method: "POST",
|
|
1425
1472
|
headers: {
|
|
@@ -1433,7 +1480,11 @@ Check PAPI_PROJECT_ID in your .mcp.json config. Find your project ID in the PAPI
|
|
|
1433
1480
|
metadata: event.metadata ?? {}
|
|
1434
1481
|
}),
|
|
1435
1482
|
signal: AbortSignal.timeout(5e3)
|
|
1436
|
-
}).
|
|
1483
|
+
}).then((res) => {
|
|
1484
|
+
if (res.ok) noteTelemetryEmitSuccess();
|
|
1485
|
+
else reportTelemetryEmitFailure(`HTTP ${res.status}`, ctx);
|
|
1486
|
+
}).catch((err) => {
|
|
1487
|
+
reportTelemetryEmitFailure(err instanceof Error ? err.name : "network error", ctx);
|
|
1437
1488
|
});
|
|
1438
1489
|
}
|
|
1439
1490
|
readToolMetrics() {
|
|
@@ -1525,6 +1576,19 @@ Check PAPI_PROJECT_ID in your .mcp.json config. Find your project ID in the PAPI
|
|
|
1525
1576
|
getStrategyReviews(limit, includeFullAnalysis) {
|
|
1526
1577
|
return this.invoke("getStrategyReviews", [limit, includeFullAnalysis]);
|
|
1527
1578
|
}
|
|
1579
|
+
// --- Strategy Review Agenda (SUP-2026-026 — hosted parity) ---
|
|
1580
|
+
// Present on the pg/md adapters since C302 but never forwarded here, so
|
|
1581
|
+
// `strategy_agenda` failed for every hosted user. The proxy-parity guard missed
|
|
1582
|
+
// it because it only checked forwarded⊆allowed, never pg⊆forwarded (now fixed).
|
|
1583
|
+
addAgendaTopic(input) {
|
|
1584
|
+
return this.invoke("addAgendaTopic", [input]);
|
|
1585
|
+
}
|
|
1586
|
+
getPendingAgendaTopics() {
|
|
1587
|
+
return this.invoke("getPendingAgendaTopics");
|
|
1588
|
+
}
|
|
1589
|
+
markAgendaTopicsAddressed(ids, cycleNumber) {
|
|
1590
|
+
return this.invoke("markAgendaTopicsAddressed", [ids, cycleNumber]);
|
|
1591
|
+
}
|
|
1528
1592
|
// --- Dogfood ---
|
|
1529
1593
|
writeDogfoodEntries(entries) {
|
|
1530
1594
|
return this.invoke("writeDogfoodEntries", [entries]);
|
|
@@ -1763,12 +1827,12 @@ import { pathToFileURL } from "url";
|
|
|
1763
1827
|
import path2 from "path";
|
|
1764
1828
|
import { execSync } from "child_process";
|
|
1765
1829
|
|
|
1766
|
-
//
|
|
1830
|
+
// ../../../../../packages/adapter-md/dist/index.js
|
|
1767
1831
|
import { readFile, writeFile, access } from "fs/promises";
|
|
1768
1832
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
1769
1833
|
import { join } from "path";
|
|
1770
1834
|
|
|
1771
|
-
//
|
|
1835
|
+
// ../../../../../packages/shared/dist/index.js
|
|
1772
1836
|
var VALID_TRANSITIONS = {
|
|
1773
1837
|
"Backlog": ["In Cycle", "Ready", "In Progress", "Blocked", "Cancelled", "Deferred", "Done"],
|
|
1774
1838
|
"In Cycle": ["In Progress", "Backlog", "Blocked", "Cancelled"],
|
|
@@ -1787,7 +1851,7 @@ function isLiveDecision(d) {
|
|
|
1787
1851
|
return true;
|
|
1788
1852
|
}
|
|
1789
1853
|
|
|
1790
|
-
//
|
|
1854
|
+
// ../../../../../packages/adapter-md/dist/index.js
|
|
1791
1855
|
import { randomUUID } from "crypto";
|
|
1792
1856
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
1793
1857
|
import yaml from "js-yaml";
|
|
@@ -4064,8 +4128,8 @@ function detectUserId() {
|
|
|
4064
4128
|
}
|
|
4065
4129
|
return void 0;
|
|
4066
4130
|
}
|
|
4067
|
-
var
|
|
4068
|
-
var HOSTED_PROXY_ENDPOINT = `${
|
|
4131
|
+
var HOSTED_SUPABASE_URL2 = process.env["PAPI_HOSTED_SUPABASE_URL"] ?? "https://guewgygcpcmrcoppihzx.supabase.co";
|
|
4132
|
+
var HOSTED_PROXY_ENDPOINT = `${HOSTED_SUPABASE_URL2}/functions/v1/data-proxy`;
|
|
4069
4133
|
var PLACEHOLDER_PATTERNS = [
|
|
4070
4134
|
"<YOUR_DATABASE_URL>",
|
|
4071
4135
|
"your-database-url",
|