paneltir 0.10.0 → 0.10.1
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/INSTALL.md +2 -2
- package/README.md +1 -1
- package/bin/paneltir.mjs +81 -8
- package/dist/index.d.ts +12 -0
- package/dist/index.js +13 -9
- package/fingerprint.json +4 -4
- package/package.json +29 -15
- package/template/api/panel-state.ts +23 -3
package/INSTALL.md
CHANGED
|
@@ -19,7 +19,7 @@ identity** — never another project's.
|
|
|
19
19
|
npm install paneltir
|
|
20
20
|
|
|
21
21
|
# or, without npm access, straight from the repository:
|
|
22
|
-
# npm install github:daifukus/paneltir#v0.10.
|
|
22
|
+
# npm install github:daifukus/paneltir#v0.10.1
|
|
23
23
|
```
|
|
24
24
|
|
|
25
25
|
(Use the tag you were given; never install without pinning a version.)
|
|
@@ -237,7 +237,7 @@ identity** — never another project's.
|
|
|
237
237
|
|
|
238
238
|
```bash
|
|
239
239
|
npx paneltir version # version, fingerprint, where it came from
|
|
240
|
-
npx paneltir check 0.10.
|
|
240
|
+
npx paneltir check 0.10.1 # exits non-zero if that is not what is installed
|
|
241
241
|
npx paneltir board # read the board and say what is wrong with it
|
|
242
242
|
```
|
|
243
243
|
|
package/README.md
CHANGED
|
@@ -54,7 +54,7 @@ tag rather than a branch, so an unfinished push cannot reach a project:
|
|
|
54
54
|
npm install paneltir
|
|
55
55
|
|
|
56
56
|
# or, without npm access, straight from the repository:
|
|
57
|
-
# npm install github:daifukus/paneltir#v0.10.
|
|
57
|
+
# npm install github:daifukus/paneltir#v0.10.1
|
|
58
58
|
```
|
|
59
59
|
|
|
60
60
|
Installing from Git runs the `prepare` script, which builds `dist/`, so the
|
package/bin/paneltir.mjs
CHANGED
|
@@ -130,10 +130,35 @@ function writeStamp(target, templateFiles, written) {
|
|
|
130
130
|
const files = { ...(previous?.files ?? {}) }
|
|
131
131
|
for (const file of written) files[file] = sha256(join(target, file))
|
|
132
132
|
|
|
133
|
+
/*
|
|
134
|
+
* The headline only advances when this run actually rewrote the whole gate.
|
|
135
|
+
*
|
|
136
|
+
* It used to advance on every run, which quietly defeated the entire point.
|
|
137
|
+
* A project on v0.9.0, a template changed in v0.10.0, `npm update`, then a
|
|
138
|
+
* re-run of `init` — which writes nothing, because the files are already
|
|
139
|
+
* there — and the stamp said the gate came from v0.10.0 while the files on
|
|
140
|
+
* disk were still v0.9.0's. `doctor` then printed "The template has not
|
|
141
|
+
* changed since" directly above a row reading BEHIND, and the panel, which
|
|
142
|
+
* has only this hash to go on, said the gate was current. Reproduced before
|
|
143
|
+
* fixing.
|
|
144
|
+
*
|
|
145
|
+
* The board is excluded because it is never rewritten: requiring it would
|
|
146
|
+
* mean the headline never advanced at all after the first install.
|
|
147
|
+
*
|
|
148
|
+
* When the gate is mixed — some files written, some left — the previous
|
|
149
|
+
* answer stands. That can over-report staleness for a partly updated gate,
|
|
150
|
+
* and it is the safe direction: `doctor`'s per-file rows carry the truth,
|
|
151
|
+
* and over-reporting sends somebody to read a diff while under-reporting
|
|
152
|
+
* sends them nowhere at all.
|
|
153
|
+
*/
|
|
154
|
+
const gateFiles = templateFiles.filter((file) => file !== BOARD_SEED)
|
|
155
|
+
const wholeGate = gateFiles.length > 0 && gateFiles.every((file) => written.includes(file))
|
|
156
|
+
|
|
133
157
|
const stamp = {
|
|
134
|
-
version: pkg.version,
|
|
135
|
-
templateHash: fingerprint.templateHash ?? '',
|
|
136
|
-
|
|
158
|
+
version: wholeGate ? pkg.version : (previous?.version ?? pkg.version),
|
|
159
|
+
templateHash: wholeGate ? (fingerprint.templateHash ?? '') : (previous?.templateHash ?? ''),
|
|
160
|
+
// When this gate was last written, not when this command last ran.
|
|
161
|
+
copiedAt: written.length ? new Date().toISOString() : (previous?.copiedAt ?? new Date().toISOString()),
|
|
137
162
|
files,
|
|
138
163
|
}
|
|
139
164
|
try {
|
|
@@ -513,9 +538,33 @@ function doctor() {
|
|
|
513
538
|
* behalf would be the second thing in this project writing to their
|
|
514
539
|
* repository.
|
|
515
540
|
*/
|
|
541
|
+
/**
|
|
542
|
+
* One flag, in either form, because the usage line prints the space one.
|
|
543
|
+
*
|
|
544
|
+
* It only read `--cards=a,b`, while its own error message printed
|
|
545
|
+
* `[--cards a,b]` — so the documented form took `a,b` as the board path and
|
|
546
|
+
* failed with "no board at a,b", and `--by you` was dropped silently, which is
|
|
547
|
+
* worse: the run was attributed to Claude when somebody said it was theirs.
|
|
548
|
+
*/
|
|
549
|
+
function flag(args, name) {
|
|
550
|
+
const joined = args.find((a) => a.startsWith(`--${name}=`))
|
|
551
|
+
if (joined) return joined.slice(name.length + 3)
|
|
552
|
+
const at = args.indexOf(`--${name}`)
|
|
553
|
+
if (at !== -1 && typeof args[at + 1] === 'string' && !args[at + 1].startsWith('--')) return args[at + 1]
|
|
554
|
+
return undefined
|
|
555
|
+
}
|
|
556
|
+
|
|
516
557
|
async function run(args) {
|
|
517
|
-
|
|
518
|
-
const
|
|
558
|
+
// A flag's value is not a positional argument, whichever form it came in.
|
|
559
|
+
const taken = new Set()
|
|
560
|
+
for (const name of ['cards', 'by']) {
|
|
561
|
+
const at = args.indexOf(`--${name}`)
|
|
562
|
+
if (at !== -1) {
|
|
563
|
+
taken.add(at)
|
|
564
|
+
if (typeof args[at + 1] === 'string' && !args[at + 1].startsWith('--')) taken.add(at + 1)
|
|
565
|
+
}
|
|
566
|
+
}
|
|
567
|
+
const plain = args.filter((a, i) => !a.startsWith('--') && !taken.has(i))
|
|
519
568
|
const summary = plain[0]
|
|
520
569
|
const file = plain[1] ?? BOARD_SEED
|
|
521
570
|
|
|
@@ -543,7 +592,7 @@ async function run(args) {
|
|
|
543
592
|
}
|
|
544
593
|
|
|
545
594
|
const board = check.board
|
|
546
|
-
const cards = (
|
|
595
|
+
const cards = (flag(args, 'cards') ?? '')
|
|
547
596
|
.split(',')
|
|
548
597
|
.map((id) => id.trim())
|
|
549
598
|
.filter(Boolean)
|
|
@@ -557,10 +606,15 @@ async function run(args) {
|
|
|
557
606
|
process.exit(1)
|
|
558
607
|
}
|
|
559
608
|
|
|
560
|
-
const by =
|
|
609
|
+
const by = flag(args, 'by') === 'you' ? 'you' : 'claude'
|
|
561
610
|
const date = new Date().toISOString().slice(0, 10)
|
|
562
611
|
board.runs = Array.isArray(board.runs) ? board.runs : []
|
|
563
|
-
|
|
612
|
+
// Appended, not prepended: `runs` is stored oldest-first and every reader
|
|
613
|
+
// reverses it. `unshift` put a new pass at the *oldest* position, so it
|
|
614
|
+
// rendered at the bottom of the revisions log and fell outside the bell's
|
|
615
|
+
// newest-first window — a record of work that read as the first thing ever
|
|
616
|
+
// done here.
|
|
617
|
+
board.runs.push({
|
|
564
618
|
id: `run-${date}-${String(board.runs.length + 1).padStart(3, '0')}`,
|
|
565
619
|
date,
|
|
566
620
|
by,
|
|
@@ -569,8 +623,27 @@ async function run(args) {
|
|
|
569
623
|
fingerprint: shortHash,
|
|
570
624
|
})
|
|
571
625
|
|
|
626
|
+
/*
|
|
627
|
+
* Bounded here, because here is where it grows.
|
|
628
|
+
*
|
|
629
|
+
* The validators used to refuse a board with more than 200 runs while
|
|
630
|
+
* nothing anywhere trimmed them, so the only reachable outcome was a Save
|
|
631
|
+
* that broke permanently on the two-hundredth pass and said "Too many runs".
|
|
632
|
+
* A bound belongs where the list is appended, not where it is read: trimming
|
|
633
|
+
* on the write path would commit a board shorter than the one the panel is
|
|
634
|
+
* holding, and the panel would read as saved while the repository disagreed.
|
|
635
|
+
*
|
|
636
|
+
* The oldest go, since `runs` is oldest-first. Three hundred is about a
|
|
637
|
+
* decade of daily passes, and the diff of a list that only grows grows with
|
|
638
|
+
* it.
|
|
639
|
+
*/
|
|
640
|
+
const KEEP_RUNS = 300
|
|
641
|
+
const dropped = Math.max(0, board.runs.length - KEEP_RUNS)
|
|
642
|
+
if (dropped) board.runs = board.runs.slice(dropped)
|
|
643
|
+
|
|
572
644
|
writeFileSync(path, JSON.stringify(board, null, 2) + '\n')
|
|
573
645
|
console.log(`Appended to ${file}: ${summary}`)
|
|
646
|
+
if (dropped) console.log(` dropped the ${dropped} oldest run(s), keeping the last ${KEEP_RUNS}`)
|
|
574
647
|
console.log(` ${cards.length ? `cards ${cards.join(', ')}` : 'no cards named'} · by ${by} · ${shortHash}`)
|
|
575
648
|
console.log('\nThe file is changed and not committed. The panel commits it on Save,')
|
|
576
649
|
console.log('or commit it yourself — this writes nothing to your repository.')
|
package/dist/index.d.ts
CHANGED
|
@@ -521,6 +521,18 @@ interface SetupRequirement {
|
|
|
521
521
|
enables?: React.ReactNode;
|
|
522
522
|
/** Exactly what to do, shown only when it is missing. */
|
|
523
523
|
fix?: React.ReactNode;
|
|
524
|
+
/**
|
|
525
|
+
* Information rather than a gate: drawn in the list, never walked as a step.
|
|
526
|
+
*
|
|
527
|
+
* Every other requirement here is an environment variable, and the
|
|
528
|
+
* walkthrough's one action — re-read the environment from the server —
|
|
529
|
+
* is what clears it. A requirement that action cannot clear parks the
|
|
530
|
+
* walkthrough on it for ever, and because `unknown` is judged across the
|
|
531
|
+
* whole list, one advisory row that nobody wired made every step answer a
|
|
532
|
+
* successful check with "the panel could not ask its own server". That is
|
|
533
|
+
* what the copied gate did the day it was added.
|
|
534
|
+
*/
|
|
535
|
+
advisory?: boolean;
|
|
524
536
|
}
|
|
525
537
|
interface SetupGuideProps {
|
|
526
538
|
requirements: SetupRequirement[];
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
// src/version.ts
|
|
2
|
-
var PANELTIR_VERSION = "0.10.
|
|
3
|
-
var PANELTIR_FINGERPRINT = "sha256:
|
|
2
|
+
var PANELTIR_VERSION = "0.10.1";
|
|
3
|
+
var PANELTIR_FINGERPRINT = "sha256:b2d1daf120972ce3bfc54f3a9f09bccaddd6ceb306a65a1682b810012d85f33d";
|
|
4
4
|
var PANELTIR_FILE_COUNT = 163;
|
|
5
|
-
var PANELTIR_TEMPLATE_HASH = "sha256:
|
|
5
|
+
var PANELTIR_TEMPLATE_HASH = "sha256:034ba27266408af4f2ba5793d9cefbe448b168570d6a0b87dfe698dfe639feb1";
|
|
6
6
|
var paneltirBuild = {
|
|
7
7
|
version: PANELTIR_VERSION,
|
|
8
8
|
fingerprint: PANELTIR_FINGERPRINT,
|
|
@@ -918,15 +918,16 @@ import { useState as useState5 } from "react";
|
|
|
918
918
|
|
|
919
919
|
// src/components/Setup/wizard.ts
|
|
920
920
|
function wizardStep(requirements) {
|
|
921
|
-
const
|
|
922
|
-
const
|
|
923
|
-
const
|
|
924
|
-
const
|
|
921
|
+
const steps = requirements.filter((requirement) => !requirement.advisory);
|
|
922
|
+
const total = steps.length;
|
|
923
|
+
const done = steps.filter((requirement) => requirement.status === "ok");
|
|
924
|
+
const unknown = steps.some((requirement) => requirement.status === "unknown");
|
|
925
|
+
const at = steps.findIndex((requirement) => requirement.status !== "ok");
|
|
925
926
|
if (at === -1) {
|
|
926
927
|
return { current: null, index: 0, total, done, ready: total > 0, unknown: false };
|
|
927
928
|
}
|
|
928
929
|
return {
|
|
929
|
-
current:
|
|
930
|
+
current: steps[at],
|
|
930
931
|
index: at + 1,
|
|
931
932
|
total,
|
|
932
933
|
done,
|
|
@@ -2939,7 +2940,7 @@ function applyMove(cards, move, visible) {
|
|
|
2939
2940
|
function resolveTheme(saved, stored, themes, hasImported, fallback) {
|
|
2940
2941
|
for (const name of [saved, stored]) {
|
|
2941
2942
|
if (name === "imported" && hasImported) return "imported";
|
|
2942
|
-
if (name && name
|
|
2943
|
+
if (name && Object.prototype.hasOwnProperty.call(themes, name)) return name;
|
|
2943
2944
|
}
|
|
2944
2945
|
return fallback ?? Object.keys(themes)[0];
|
|
2945
2946
|
}
|
|
@@ -3108,6 +3109,9 @@ function PanelApp({
|
|
|
3108
3109
|
// `SetupWizard` already refuses to make.
|
|
3109
3110
|
...gate === void 0 ? [] : [{
|
|
3110
3111
|
id: "gate",
|
|
3112
|
+
// Information, not a gate: the walkthrough's only action re-reads the
|
|
3113
|
+
// environment, and this is files on disk. See SetupRequirement.
|
|
3114
|
+
advisory: true,
|
|
3111
3115
|
label: ui.needGate,
|
|
3112
3116
|
status: gateReading.verdict === "current" ? "ok" : gateReading.verdict === "behind" ? "missing" : "unknown",
|
|
3113
3117
|
enables: ui.needGateEnables,
|
package/fingerprint.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "paneltir",
|
|
3
|
-
"version": "0.10.
|
|
4
|
-
"hash": "sha256:
|
|
3
|
+
"version": "0.10.1",
|
|
4
|
+
"hash": "sha256:b2d1daf120972ce3bfc54f3a9f09bccaddd6ceb306a65a1682b810012d85f33d",
|
|
5
5
|
"fileCount": 163,
|
|
6
|
-
"templateHash": "sha256:
|
|
7
|
-
"generatedAt": "2026-09-
|
|
6
|
+
"templateHash": "sha256:034ba27266408af4f2ba5793d9cefbe448b168570d6a0b87dfe698dfe639feb1",
|
|
7
|
+
"generatedAt": "2026-09-11T07:08:17.308Z"
|
|
8
8
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "paneltir",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "A React UI kit for admin panels: page frame, a board with touch-ready drag and drop, detail sheets, and a whole panel in one component. Structure and behaviour are fixed; colour and brand belong to each project.",
|
|
5
5
|
"license": "SEE LICENSE IN LICENSE",
|
|
6
6
|
"author": "DFKlabs (https://DFKlabs.com)",
|
|
@@ -99,42 +99,56 @@
|
|
|
99
99
|
"node": ">=20"
|
|
100
100
|
},
|
|
101
101
|
"paneltirRelease": {
|
|
102
|
-
"version": "0.10.
|
|
102
|
+
"version": "0.10.1",
|
|
103
103
|
"date": "2026-09-11",
|
|
104
104
|
"entries": [
|
|
105
105
|
{
|
|
106
|
-
"kind": "
|
|
106
|
+
"kind": "fix",
|
|
107
107
|
"text": {
|
|
108
|
-
"en": "`paneltir
|
|
109
|
-
"es": "`paneltir
|
|
108
|
+
"en": "Re-running `paneltir init` no longer tells the panel a stale gate is current. It stamped the new template over files it had not written, so a project that updated and re-ran init was told its gate was up to date when it was not.",
|
|
109
|
+
"es": "Re-ejecutar `paneltir init` ya no le dice al panel que una puerta vieja está al día. Sellaba la plantilla nueva sobre archivos que no había escrito, así que un proyecto que actualizaba y re-ejecutaba init recibía un «todo correcto» que no era cierto."
|
|
110
110
|
}
|
|
111
111
|
},
|
|
112
112
|
{
|
|
113
|
-
"kind": "
|
|
113
|
+
"kind": "fix",
|
|
114
|
+
"text": {
|
|
115
|
+
"en": "The save endpoint's own board check had drifted to a shallow one that accepted a board with no areas, an unknown intent, an unknown area and any version at all. All three copies of that check are now held to the same verdict.",
|
|
116
|
+
"es": "La comprobación del tablero en el endpoint de guardado había derivado a una superficial que aceptaba un tablero sin áreas, un intent desconocido, un área desconocida y cualquier versión. Las tres copias de esa comprobación se sujetan ahora al mismo veredicto."
|
|
117
|
+
}
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
"kind": "fix",
|
|
114
121
|
"text": {
|
|
115
|
-
"en": "
|
|
116
|
-
"es": "
|
|
122
|
+
"en": "`paneltir run` appends to the end of the revisions log instead of the front, so a new pass reads as the newest and not the oldest — and accepts `--cards a,b` and `--by you`, the spaced form its own usage line prints.",
|
|
123
|
+
"es": "`paneltir run` añade al final del registro de revisiones en vez de al principio, así una pasada nueva se lee como la más reciente y no como la más antigua — y acepta `--cards a,b` y `--by you`, la forma con espacio que imprime su propio uso."
|
|
117
124
|
}
|
|
118
125
|
},
|
|
119
126
|
{
|
|
120
|
-
"kind": "
|
|
127
|
+
"kind": "fix",
|
|
128
|
+
"text": {
|
|
129
|
+
"en": "A board naming a theme that only exists on Object's prototype — `constructor`, `toString` — no longer resolves as a theme and draws the panel in the browser's default colours.",
|
|
130
|
+
"es": "Un tablero que nombra un tema que sólo existe en el prototipo de Object — `constructor`, `toString` — ya no se resuelve como tema ni dibuja el panel con los colores por defecto del navegador."
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
"kind": "fix",
|
|
121
135
|
"text": {
|
|
122
|
-
"en": "
|
|
123
|
-
"es": "
|
|
136
|
+
"en": "Saving no longer breaks permanently once a board reaches two hundred revisions. The limit was refused on the write path and applied nowhere; it is bounded where the log is appended instead.",
|
|
137
|
+
"es": "Guardar ya no se rompe para siempre cuando un tablero llega a doscientas revisiones. El límite se rechazaba al escribir y no se aplicaba en ningún sitio; ahora se acota donde se añade al registro."
|
|
124
138
|
}
|
|
125
139
|
},
|
|
126
140
|
{
|
|
127
141
|
"kind": "fix",
|
|
128
142
|
"text": {
|
|
129
|
-
"en": "
|
|
130
|
-
"es": "
|
|
143
|
+
"en": "The copied gate's row in the setup list no longer parks the walkthrough on a step its one action cannot clear, nor makes every other step report that the panel could not reach its own server.",
|
|
144
|
+
"es": "La fila de la puerta copiada en la lista de configuración ya no deja el asistente atascado en un paso que su única acción no puede resolver, ni hace que el resto de pasos digan que el panel no pudo alcanzar su propio servidor."
|
|
131
145
|
}
|
|
132
146
|
},
|
|
133
147
|
{
|
|
134
148
|
"kind": "chore",
|
|
135
149
|
"text": {
|
|
136
|
-
"en": "
|
|
137
|
-
"es": "Se
|
|
150
|
+
"en": "Two checks that could stop checking were closed: a travelling document that cannot be read is now a failure rather than a pass, and no gate file may read the environment at module scope — where no error can be caught.",
|
|
151
|
+
"es": "Se cerraron dos comprobaciones que podían dejar de comprobar: un documento que viaja y no se puede leer ahora falla en vez de pasar, y ningún archivo de la puerta puede leer el entorno a nivel de módulo, donde ningún error se puede capturar."
|
|
138
152
|
}
|
|
139
153
|
}
|
|
140
154
|
]
|
|
@@ -121,8 +121,22 @@ function readCookie(header: string | null | undefined, name: string): string | u
|
|
|
121
121
|
* Where the board lives in this repository. Set PANEL_FILE to override; the
|
|
122
122
|
* default is only a guess at a sensible place, and a wrong path here fails
|
|
123
123
|
* loudly on the first save rather than quietly writing somewhere else.
|
|
124
|
+
*
|
|
125
|
+
* A function, and not a constant, for the reason `env()` above is wrapped: a
|
|
126
|
+
* bare `process.env.X` is a ReferenceError wherever `process` is undefined,
|
|
127
|
+
* and at module scope it runs *before* the handler's `try` — so it cannot be
|
|
128
|
+
* caught and the platform answers `FUNCTION_INVOCATION_FAILED`, a code that
|
|
129
|
+
* names the shape of the fault and never the fault. That is the exact failure
|
|
130
|
+
* this file has already had twice, from an import and then from a throw ahead
|
|
131
|
+
* of the wrapper. This was the last module-scope read left in any gate file.
|
|
124
132
|
*/
|
|
125
|
-
|
|
133
|
+
function filePath(): string {
|
|
134
|
+
try {
|
|
135
|
+
return process.env.PANEL_FILE || 'src/data/panel-state.json'
|
|
136
|
+
} catch {
|
|
137
|
+
return 'src/data/panel-state.json'
|
|
138
|
+
}
|
|
139
|
+
}
|
|
126
140
|
const MAX_BODY_BYTES = 512 * 1024
|
|
127
141
|
|
|
128
142
|
interface VercelRequest {
|
|
@@ -277,6 +291,12 @@ function invalidState(state: unknown): string | null {
|
|
|
277
291
|
}
|
|
278
292
|
|
|
279
293
|
if (!Array.isArray(state.runs)) say('runs', 'must be an array')
|
|
294
|
+
// Deliberately no cap. The shape is checked here; how long a log may get is
|
|
295
|
+
// not a shape, and refusing a board for having too much history is a panel
|
|
296
|
+
// that stops saving one day and never says why. This copy used to refuse
|
|
297
|
+
// over 200 runs while nothing anywhere trimmed them, so the only outcome was
|
|
298
|
+
// a Save that broke permanently on the two-hundredth pass. Bounded on write
|
|
299
|
+
// instead, where a bound can be applied rather than only enforced.
|
|
280
300
|
|
|
281
301
|
return problems.length ? problems.join('; ') : null
|
|
282
302
|
}
|
|
@@ -302,7 +322,7 @@ function configuration() {
|
|
|
302
322
|
// is how a misconfigured target gets noticed before it is written to.
|
|
303
323
|
repo: repo ?? null,
|
|
304
324
|
branch: process.env.PANEL_BRANCH || 'main',
|
|
305
|
-
file:
|
|
325
|
+
file: filePath(),
|
|
306
326
|
}
|
|
307
327
|
}
|
|
308
328
|
|
|
@@ -373,7 +393,7 @@ async function handleRequest(request: VercelRequest, response: VercelResponse) {
|
|
|
373
393
|
? payload.message.trim().slice(0, 120)
|
|
374
394
|
: 'chore(panel): update the board from the panel'
|
|
375
395
|
|
|
376
|
-
const api = `https://api.github.com/repos/${repo}/contents/${
|
|
396
|
+
const api = `https://api.github.com/repos/${repo}/contents/${filePath()}`
|
|
377
397
|
const githubHeaders = {
|
|
378
398
|
authorization: `Bearer ${token}`,
|
|
379
399
|
accept: 'application/vnd.github+json',
|