pageship 0.6.1 → 0.7.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 +1 -1
- package/dist/cli.mjs +301 -15
- package/dist/skills/pageship/SKILL.md +19 -4
- package/dist/skills/pageship/references/download.md +2 -2
- package/dist/skills/pageship/references/read.md +17 -0
- package/dist/skills/pageship-chart/SKILL.md +1 -1
- package/dist/skills/pageship-code-block/SKILL.md +1 -1
- package/dist/skills/pageship-decision-record/SKILL.md +1 -1
- package/dist/skills/pageship-diagram/SKILL.md +1 -1
- package/dist/skills/pageship-docs/SKILL.md +1 -1
- package/dist/skills/pageship-explainer/SKILL.md +1 -1
- package/dist/skills/pageship-interaction/SKILL.md +1 -1
- package/dist/skills/pageship-key-figures/SKILL.md +1 -1
- package/dist/skills/pageship-media/SKILL.md +1 -1
- package/dist/skills/pageship-motion/SKILL.md +1 -1
- package/dist/skills/pageship-plan/SKILL.md +1 -1
- package/dist/skills/pageship-report/SKILL.md +1 -1
- package/dist/skills/pageship-review-report/SKILL.md +1 -1
- package/dist/skills/pageship-slide-deck/SKILL.md +1 -1
- package/dist/skills/pageship-spec/SKILL.md +1 -1
- package/dist/skills/pageship-table/SKILL.md +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Pageship CLI
|
|
2
2
|
|
|
3
|
-
Pageship is an HTML publishing service in development. This CLI signs you in to the hosted Pageship service through a browser, publishes HTML files as documents behind stable links, and lists, downloads, restores and changes the visibility of the documents you published. It also installs the Pageship skills for your agents.
|
|
3
|
+
Pageship is an HTML publishing service in development. This CLI signs you in to the hosted Pageship service through a browser, publishes HTML files as documents behind stable links, and lists, downloads, restores and changes the visibility of the documents you published. It also reads documents other people shared with you, by their links. It also installs the Pageship skills for your agents.
|
|
4
4
|
|
|
5
5
|
The full reference, with every command, option and result, is at https://pageship.dev/docs/cli.
|
|
6
6
|
|
package/dist/cli.mjs
CHANGED
|
@@ -675,6 +675,18 @@ const documentsRestore = (options) => (options.client ?? client).post({
|
|
|
675
675
|
...options.headers
|
|
676
676
|
}
|
|
677
677
|
});
|
|
678
|
+
const installationsList = (options) => (options?.client ?? client).get({
|
|
679
|
+
url: "/api/v1/installations",
|
|
680
|
+
...options
|
|
681
|
+
});
|
|
682
|
+
const installationsRevoke = (options) => (options.client ?? client).post({
|
|
683
|
+
url: "/api/v1/installations/revoke",
|
|
684
|
+
...options,
|
|
685
|
+
headers: {
|
|
686
|
+
"Content-Type": "application/json",
|
|
687
|
+
...options.headers
|
|
688
|
+
}
|
|
689
|
+
});
|
|
678
690
|
const viewersList = (options) => (options.client ?? client).get({
|
|
679
691
|
url: "/api/v1/documents/{id}/viewers",
|
|
680
692
|
...options
|
|
@@ -701,6 +713,23 @@ const workspaceDomainPattern = workspaceDomain.replaceAll(".", "\\.");
|
|
|
701
713
|
const workspaceHostname = (subdomain) => `${subdomain}.${workspaceDomain}`;
|
|
702
714
|
/** A valid workspace label: the subdomain of one workspace address, as a DNS label. */
|
|
703
715
|
const workspaceLabelPattern = /^[a-z\d](?:[a-z\d-]{0,61}[a-z\d])?$/u;
|
|
716
|
+
/**
|
|
717
|
+
* Service names that are never a workspace. Migration `0002_personal_subdomains.sql` reserves
|
|
718
|
+
* them in the address table, and readiness checks that the table still holds each one.
|
|
719
|
+
*/
|
|
720
|
+
const reservedWorkspaceSubdomains = [
|
|
721
|
+
"www",
|
|
722
|
+
"api",
|
|
723
|
+
"app",
|
|
724
|
+
"auth",
|
|
725
|
+
"admin",
|
|
726
|
+
"dashboard",
|
|
727
|
+
"docs",
|
|
728
|
+
"status",
|
|
729
|
+
"support",
|
|
730
|
+
"mail",
|
|
731
|
+
"pageship"
|
|
732
|
+
];
|
|
704
733
|
//#endregion
|
|
705
734
|
//#region ../../packages/api-client/src/address.ts
|
|
706
735
|
/** Generated TypeScript does not validate remote JSON, so check an address before showing it. */
|
|
@@ -858,7 +887,11 @@ async function getDocumentRevisions(baseUrl, id, options = {}) {
|
|
|
858
887
|
};
|
|
859
888
|
throw new Error("Invalid document revision listing response.");
|
|
860
889
|
}
|
|
861
|
-
/**
|
|
890
|
+
/**
|
|
891
|
+
* Exact bytes of the current revision, or of one selected historical revision. The owner reads
|
|
892
|
+
* any revision; another admitted account reads the current one of a public document, or of a
|
|
893
|
+
* private one it is a viewer of.
|
|
894
|
+
*/
|
|
862
895
|
async function getDocumentContent(baseUrl, id, options = {}) {
|
|
863
896
|
const request = {
|
|
864
897
|
...requestOptions(baseUrl, options),
|
|
@@ -1061,6 +1094,31 @@ async function getGitHubUser(baseUrl, login, options = {}) {
|
|
|
1061
1094
|
throw new Error("Invalid GitHub user response.");
|
|
1062
1095
|
}
|
|
1063
1096
|
//#endregion
|
|
1097
|
+
//#region ../../packages/api-client/src/installations.ts
|
|
1098
|
+
async function requestInstallations(baseUrl, installationId, { signal, token } = {}) {
|
|
1099
|
+
const timeout = AbortSignal.timeout(1e4);
|
|
1100
|
+
const options = {
|
|
1101
|
+
baseUrl,
|
|
1102
|
+
credentials: token ? "omit" : "include",
|
|
1103
|
+
headers: token ? { Authorization: `Bearer ${token}` } : void 0,
|
|
1104
|
+
redirect: "error",
|
|
1105
|
+
cache: "no-store",
|
|
1106
|
+
throwOnError: false,
|
|
1107
|
+
signal: signal ? AbortSignal.any([timeout, signal]) : timeout
|
|
1108
|
+
};
|
|
1109
|
+
const { data, response, error } = installationId === void 0 ? await installationsList(options) : await installationsRevoke({
|
|
1110
|
+
...options,
|
|
1111
|
+
cache: "default",
|
|
1112
|
+
body: { installationId }
|
|
1113
|
+
});
|
|
1114
|
+
if (!response?.ok) throw new Error("Could not update CLI installations. Try again.", { cause: error });
|
|
1115
|
+
if (data?.status === "signed_out" || data?.status === "uninvited" || data?.status === "unavailable" || data?.status === "revoked") return { status: data.status };
|
|
1116
|
+
if (data?.status === "listed" && Array.isArray(data.installations) && data.installations.every((entry) => entry && typeof entry.id === "string" && entry.id.length > 0 && typeof entry.createdAt === "string" && Number.isFinite(Date.parse(entry.createdAt)) && typeof entry.expiresAt === "string" && Number.isFinite(Date.parse(entry.expiresAt)))) return data;
|
|
1117
|
+
throw new Error("Invalid CLI installations response.");
|
|
1118
|
+
}
|
|
1119
|
+
/** Revoke one CLI installation. With `token`, a CLI revokes its own installation. */
|
|
1120
|
+
const revokeInstallation = (baseUrl, installationId, options) => requestInstallations(baseUrl, installationId, options);
|
|
1121
|
+
//#endregion
|
|
1064
1122
|
//#region ../../packages/api-client/src/index.ts
|
|
1065
1123
|
async function getWorkspace(baseUrl, options = {}) {
|
|
1066
1124
|
const timeout = AbortSignal.timeout(1e4);
|
|
@@ -1436,12 +1494,14 @@ const outcomes = {
|
|
|
1436
1494
|
published: "succeeded",
|
|
1437
1495
|
listed: "succeeded",
|
|
1438
1496
|
downloaded: "succeeded",
|
|
1497
|
+
read: "succeeded",
|
|
1439
1498
|
visibility_updated: "succeeded",
|
|
1440
1499
|
restored: "succeeded",
|
|
1441
1500
|
viewers_updated: "succeeded",
|
|
1442
1501
|
skills_installed: "succeeded",
|
|
1443
1502
|
cli_updated: "succeeded",
|
|
1444
1503
|
cli_current: "succeeded",
|
|
1504
|
+
logged_out: "succeeded",
|
|
1445
1505
|
authorization_pending: "pending",
|
|
1446
1506
|
expired: "pending",
|
|
1447
1507
|
signed_out: "pending",
|
|
@@ -1468,6 +1528,7 @@ const outcomes = {
|
|
|
1468
1528
|
invalid_attempt: "failed",
|
|
1469
1529
|
invalid_action: "failed",
|
|
1470
1530
|
invalid_file: "failed",
|
|
1531
|
+
invalid_document: "failed",
|
|
1471
1532
|
invalid_output: "failed",
|
|
1472
1533
|
invalid_restore: "failed",
|
|
1473
1534
|
output_exists: "failed",
|
|
@@ -1493,10 +1554,12 @@ const commandNames = [
|
|
|
1493
1554
|
"status",
|
|
1494
1555
|
"login",
|
|
1495
1556
|
"whoami",
|
|
1557
|
+
"logout",
|
|
1496
1558
|
"publish",
|
|
1497
1559
|
"list",
|
|
1498
1560
|
"history",
|
|
1499
1561
|
"download",
|
|
1562
|
+
"read",
|
|
1500
1563
|
"visibility",
|
|
1501
1564
|
"viewers",
|
|
1502
1565
|
"restore",
|
|
@@ -1551,7 +1614,7 @@ function commandLine(command, args) {
|
|
|
1551
1614
|
}
|
|
1552
1615
|
//#endregion
|
|
1553
1616
|
//#region package.json
|
|
1554
|
-
var version = "0.
|
|
1617
|
+
var version = "0.7.0";
|
|
1555
1618
|
//#endregion
|
|
1556
1619
|
//#region src/publish.ts
|
|
1557
1620
|
const execute = promisify(execFile);
|
|
@@ -2270,6 +2333,48 @@ async function identify(serverValue, signal) {
|
|
|
2270
2333
|
}
|
|
2271
2334
|
}
|
|
2272
2335
|
//#endregion
|
|
2336
|
+
//#region src/document-reference.ts
|
|
2337
|
+
const documentPath = /^\/d\/([^/-]+)(?:-[^/]+)?(?:\/revisions\/([^/]+))?$/u;
|
|
2338
|
+
/** True for any URL, so the value is read as a link rather than as a malformed ID. */
|
|
2339
|
+
const isUrl = (value) => URL.canParse(value);
|
|
2340
|
+
/**
|
|
2341
|
+
* Reads a document ID from `list`, or a document or revision link the user pasted.
|
|
2342
|
+
* A link must be one a workspace host would serve, on any workspace: the server decides
|
|
2343
|
+
* access, so a link to a document this account can't read gets the same answer as an
|
|
2344
|
+
* unknown ID.
|
|
2345
|
+
* `revisionId` is an explicit `--revision`; it must agree with a revision link.
|
|
2346
|
+
*/
|
|
2347
|
+
function documentReference(value, revisionId) {
|
|
2348
|
+
const named = isDocumentId(value) ? { documentId: value } : documentLink(value);
|
|
2349
|
+
if (!named) return {
|
|
2350
|
+
status: "invalid_document",
|
|
2351
|
+
message: `${value} is not a Pageship document. Use a six-character document ID from list, or a document link such as https://<workspace>.${workspaceDomain}/d/<id>-<slug>.`
|
|
2352
|
+
};
|
|
2353
|
+
if (revisionId && named.revisionId && revisionId.toLowerCase() !== named.revisionId.toLowerCase()) return {
|
|
2354
|
+
status: "invalid_document",
|
|
2355
|
+
message: `The link names revision ${named.revisionId}, but --revision names ${revisionId}. Use one of them.`
|
|
2356
|
+
};
|
|
2357
|
+
const revision = named.revisionId ?? revisionId;
|
|
2358
|
+
return {
|
|
2359
|
+
documentId: named.documentId,
|
|
2360
|
+
...revision ? { revisionId: revision } : {}
|
|
2361
|
+
};
|
|
2362
|
+
}
|
|
2363
|
+
function documentLink(value) {
|
|
2364
|
+
if (!isUrl(value)) return;
|
|
2365
|
+
const url = new URL(value);
|
|
2366
|
+
const suffix = `.${workspaceDomain}`;
|
|
2367
|
+
const label = url.hostname.slice(0, -suffix.length);
|
|
2368
|
+
if (url.protocol !== "https:" || url.port || url.username || url.password || !url.hostname.endsWith(suffix) || !workspaceLabelPattern.test(label) || reservedWorkspaceSubdomains.some((name) => name === label)) return;
|
|
2369
|
+
const [, documentId, revisionId] = documentPath.exec(url.pathname) ?? [];
|
|
2370
|
+
if (!isDocumentId(documentId)) return;
|
|
2371
|
+
if (revisionId === void 0) return { documentId };
|
|
2372
|
+
return isRevisionId(revisionId) ? {
|
|
2373
|
+
documentId,
|
|
2374
|
+
revisionId
|
|
2375
|
+
} : void 0;
|
|
2376
|
+
}
|
|
2377
|
+
//#endregion
|
|
2273
2378
|
//#region src/documents.ts
|
|
2274
2379
|
/** `1 viewer`, `2 viewers`. */
|
|
2275
2380
|
const viewerCount = (count) => `${count} viewer${count === 1 ? "" : "s"}`;
|
|
@@ -2386,12 +2491,16 @@ function invalidOutput(output, error) {
|
|
|
2386
2491
|
message: `Could not write ${output}. ${error instanceof Error ? error.message : "Check the path and try again."}`
|
|
2387
2492
|
};
|
|
2388
2493
|
}
|
|
2389
|
-
|
|
2494
|
+
/** `document` is an ID from `list` or a document or revision link; see `documentReference`. */
|
|
2495
|
+
async function downloadDocument(options) {
|
|
2496
|
+
const reference = documentReference(options.document, options.revisionId);
|
|
2497
|
+
if ("status" in reference) return reference;
|
|
2498
|
+
const { documentId, revisionId } = reference;
|
|
2390
2499
|
const output = resolve(options.output);
|
|
2391
2500
|
return asOwner(options.server, options.signal, async ({ origin }, request) => {
|
|
2392
|
-
const bytes = await getDocumentContent(origin,
|
|
2501
|
+
const bytes = await getDocumentContent(origin, documentId, {
|
|
2393
2502
|
...request,
|
|
2394
|
-
revisionId
|
|
2503
|
+
revisionId
|
|
2395
2504
|
});
|
|
2396
2505
|
let file;
|
|
2397
2506
|
try {
|
|
@@ -2414,11 +2523,48 @@ function downloadDocument(options) {
|
|
|
2414
2523
|
await file.close();
|
|
2415
2524
|
return {
|
|
2416
2525
|
status: "downloaded",
|
|
2417
|
-
documentId
|
|
2418
|
-
revisionId:
|
|
2526
|
+
documentId,
|
|
2527
|
+
revisionId: revisionId ?? null,
|
|
2419
2528
|
output,
|
|
2420
2529
|
byteLength: bytes.byteLength,
|
|
2421
|
-
message: `Saved ${bytes.byteLength} bytes of ${
|
|
2530
|
+
message: `Saved ${bytes.byteLength} bytes of ${documentId}${revisionId ? ` revision ${revisionId}` : ""} to ${output}.`
|
|
2531
|
+
};
|
|
2532
|
+
});
|
|
2533
|
+
}
|
|
2534
|
+
/**
|
|
2535
|
+
* Reads a document's HTML for printing. `document` is an ID or a link, as for download. The
|
|
2536
|
+
* owner reads any revision; anyone reads a public document's current one, and a viewer a
|
|
2537
|
+
* private one's. The server answers a document this
|
|
2538
|
+
* account can't read like a missing one, so one message covers all three.
|
|
2539
|
+
*/
|
|
2540
|
+
async function readDocument(options) {
|
|
2541
|
+
const reference = documentReference(options.document);
|
|
2542
|
+
if ("status" in reference) return reference;
|
|
2543
|
+
const { documentId, revisionId } = reference;
|
|
2544
|
+
return asOwner(options.server, options.signal, async ({ origin }, request) => {
|
|
2545
|
+
let bytes;
|
|
2546
|
+
try {
|
|
2547
|
+
bytes = await getDocumentContent(origin, documentId, {
|
|
2548
|
+
...request,
|
|
2549
|
+
revisionId
|
|
2550
|
+
});
|
|
2551
|
+
} catch (error) {
|
|
2552
|
+
if (isRefusal(error) && error.status === "unavailable") return {
|
|
2553
|
+
status: "unavailable",
|
|
2554
|
+
documentId,
|
|
2555
|
+
revisionId: revisionId ?? null,
|
|
2556
|
+
message: `${options.document} is unavailable. It doesn't exist, was deleted, or this account can't read it.${revisionId ? " Only the owner can read an earlier revision." : ""} Check the link, and that this installation is signed in as the owner or a viewer if it is private.`
|
|
2557
|
+
};
|
|
2558
|
+
throw error;
|
|
2559
|
+
}
|
|
2560
|
+
return {
|
|
2561
|
+
status: "read",
|
|
2562
|
+
documentId,
|
|
2563
|
+
revisionId: revisionId ?? null,
|
|
2564
|
+
byteLength: bytes.byteLength,
|
|
2565
|
+
html: new TextDecoder().decode(bytes),
|
|
2566
|
+
bytes,
|
|
2567
|
+
message: `Read ${bytes.byteLength} bytes of ${documentId}${revisionId ? ` revision ${revisionId}` : ""}.`
|
|
2422
2568
|
};
|
|
2423
2569
|
});
|
|
2424
2570
|
}
|
|
@@ -2489,6 +2635,111 @@ function restoreRevision(options) {
|
|
|
2489
2635
|
});
|
|
2490
2636
|
}
|
|
2491
2637
|
//#endregion
|
|
2638
|
+
//#region src/logout.ts
|
|
2639
|
+
const errorText = (error) => error instanceof Error ? error.message : String(error);
|
|
2640
|
+
const exists = (path) => lstat(path).then(() => true, (error) => {
|
|
2641
|
+
if (error.code === "ENOENT") return false;
|
|
2642
|
+
throw error;
|
|
2643
|
+
});
|
|
2644
|
+
/**
|
|
2645
|
+
* Sign this installation out: revoke its session on the server, as the dashboard's Revoke
|
|
2646
|
+
* access does, then delete the stored credential. The credential is deleted only once the
|
|
2647
|
+
* server confirms the session is gone, so a failure never leaves a live session that the user
|
|
2648
|
+
* believes has ended.
|
|
2649
|
+
*/
|
|
2650
|
+
async function logout(serverValue, signal) {
|
|
2651
|
+
const selection = selectServer(serverValue);
|
|
2652
|
+
const server = selection.origin;
|
|
2653
|
+
const retry = {
|
|
2654
|
+
command: "logout",
|
|
2655
|
+
args: [...selection.args]
|
|
2656
|
+
};
|
|
2657
|
+
const retryLine = commandLine(retry.command, retry.args);
|
|
2658
|
+
/** A failure that keeps the credential. Only a retry that can succeed gets `next`. */
|
|
2659
|
+
const credentialKept = (status, reason, retryable = true) => ({
|
|
2660
|
+
status,
|
|
2661
|
+
message: `${reason} Your credential is kept, so this installation is still signed in.${retryable ? ` Run ${retryLine} to try again.` : ""}`,
|
|
2662
|
+
...retryable ? { next: retry } : {}
|
|
2663
|
+
});
|
|
2664
|
+
const notSignedIn = "This installation is not signed in, so there was nothing to sign out of.";
|
|
2665
|
+
let store;
|
|
2666
|
+
try {
|
|
2667
|
+
const directory = configDirectory();
|
|
2668
|
+
if (isAbsolute(directory) && !await exists(directory)) return {
|
|
2669
|
+
status: "logged_out",
|
|
2670
|
+
revoked: false,
|
|
2671
|
+
message: notSignedIn
|
|
2672
|
+
};
|
|
2673
|
+
store = await credentialStore(server);
|
|
2674
|
+
} catch (error) {
|
|
2675
|
+
return credentialKept("request_failed", `Could not open the stored credential. ${errorText(error)}`);
|
|
2676
|
+
}
|
|
2677
|
+
try {
|
|
2678
|
+
const credentials = await store.read();
|
|
2679
|
+
const discarded = credentials.pending ? " An authorization code waiting for approval was discarded. If you approved it, its session may still be listed under CLI installations in the dashboard; revoke it there." : "";
|
|
2680
|
+
if (!credentials.token) {
|
|
2681
|
+
if (credentials.pending) await store.write({});
|
|
2682
|
+
return {
|
|
2683
|
+
status: "logged_out",
|
|
2684
|
+
revoked: false,
|
|
2685
|
+
message: `${notSignedIn}${discarded}`
|
|
2686
|
+
};
|
|
2687
|
+
}
|
|
2688
|
+
const token = credentials.token;
|
|
2689
|
+
let revoked;
|
|
2690
|
+
try {
|
|
2691
|
+
const compatibility = await checkCompatibility(server, { signal });
|
|
2692
|
+
if (compatibility.status !== "compatible") return {
|
|
2693
|
+
...compatibility,
|
|
2694
|
+
...credentialKept(compatibility.status, compatibility.message, false)
|
|
2695
|
+
};
|
|
2696
|
+
const access = await getWorkspace(server, {
|
|
2697
|
+
token,
|
|
2698
|
+
signal
|
|
2699
|
+
});
|
|
2700
|
+
const notAdmitted = {
|
|
2701
|
+
status: "uninvited",
|
|
2702
|
+
message: `This account is no longer admitted to this Pageship server, so the server already refuses every request from this installation. It did not remove the installation, though. To sign out fully, ask the server owner to admit the account again and then run ${retryLine}, or to remove the installation. Your credential is kept.`
|
|
2703
|
+
};
|
|
2704
|
+
if (access.status === "uninvited") return notAdmitted;
|
|
2705
|
+
if (access.status === "signed_out") revoked = false;
|
|
2706
|
+
else if (!access.installation) return credentialKept("unsupported", "This server does not report the CLI installation, so the CLI cannot revoke it. Update the server, or revoke the installation in the dashboard under CLI installations.", false);
|
|
2707
|
+
else {
|
|
2708
|
+
const result = await revokeInstallation(server, access.installation.id, {
|
|
2709
|
+
token,
|
|
2710
|
+
signal
|
|
2711
|
+
});
|
|
2712
|
+
if (result.status === "uninvited") return notAdmitted;
|
|
2713
|
+
if (result.status === "revoked") revoked = true;
|
|
2714
|
+
else if (result.status === "signed_out") revoked = false;
|
|
2715
|
+
else return credentialKept("request_failed", "The server did not revoke this installation.");
|
|
2716
|
+
}
|
|
2717
|
+
} catch (error) {
|
|
2718
|
+
if (signal.aborted) return credentialKept("interrupted", "Sign-out was interrupted, and the server may not have revoked this installation.");
|
|
2719
|
+
return credentialKept("request_failed", `Could not sign out through the Pageship server. ${errorText(error)}`);
|
|
2720
|
+
}
|
|
2721
|
+
try {
|
|
2722
|
+
await store.write({});
|
|
2723
|
+
} catch (error) {
|
|
2724
|
+
return {
|
|
2725
|
+
status: "request_failed",
|
|
2726
|
+
revoked,
|
|
2727
|
+
message: `The server ${revoked ? "revoked this installation" : "had already revoked or expired this credential"}, but the stored credential could not be deleted. ${errorText(error)} Run ${retryLine} to delete it.`,
|
|
2728
|
+
next: retry
|
|
2729
|
+
};
|
|
2730
|
+
}
|
|
2731
|
+
return {
|
|
2732
|
+
status: "logged_out",
|
|
2733
|
+
revoked,
|
|
2734
|
+
message: `${revoked ? "Signed out. The server revoked this installation, and its stored credential is deleted." : "Signed out. The server had already revoked or expired this credential, and the stored copy is deleted."}${discarded}`
|
|
2735
|
+
};
|
|
2736
|
+
} catch (error) {
|
|
2737
|
+
return credentialKept("request_failed", `Could not use the stored credential. ${errorText(error)}`);
|
|
2738
|
+
} finally {
|
|
2739
|
+
await store.close();
|
|
2740
|
+
}
|
|
2741
|
+
}
|
|
2742
|
+
//#endregion
|
|
2492
2743
|
//#region src/skill-files.ts
|
|
2493
2744
|
const frontmatter = /^---\r?\n([\s\S]*?)\r?\n---(?=\r?\n|$)/u;
|
|
2494
2745
|
/** The CLI version a packed SKILL.md was stamped with, or undefined for an unstamped one. */
|
|
@@ -3286,6 +3537,7 @@ const login = Command.make("login", {
|
|
|
3286
3537
|
});
|
|
3287
3538
|
})).pipe(Command.withDescription("Authorize this installation through a browser and choose your workspace address."));
|
|
3288
3539
|
const whoami = Command.make("whoami", { server: serverFlag }, ({ server }) => authCommand("whoami", (signal) => identify(Option.getOrUndefined(server), signal))).pipe(Command.withDescription("Identify your personal workspace using the stored credential."));
|
|
3540
|
+
const logoutCommand = Command.make("logout", { server: serverFlag }, ({ server }) => authCommand("logout", (signal) => logout(Option.getOrUndefined(server), signal))).pipe(Command.withDescription("Sign this installation out: revoke its access on the server, then delete the stored credential."));
|
|
3289
3541
|
const idempotencyKeyFlag = Flag.string("idempotency-key").pipe(Flag.filter((value) => /^[A-Za-z0-9_-]{8,128}$/u.test(value), () => "Use an 8-128 character idempotency key containing letters, digits, underscores or hyphens."), Flag.withDescription("Retry an uncertain operation with the key its result returned."), Flag.optional);
|
|
3290
3542
|
const publishCommand = Command.make("publish", {
|
|
3291
3543
|
file: Argument.string("file"),
|
|
@@ -3330,18 +3582,34 @@ const history = Command.make("history", {
|
|
|
3330
3582
|
cursor: Option.getOrUndefined(cursor),
|
|
3331
3583
|
signal
|
|
3332
3584
|
}))).pipe(Command.withDescription("List a document's revisions, newest first, 50 per page."));
|
|
3585
|
+
const documentArgument = Argument.string("document").pipe(Argument.filter((value) => isDocumentId(value) || isUrl(value), () => "Use a six-character document ID from list, or the document's https:// link."), Argument.withDescription("Six-character document ID from list, or the document's link, including a revision link."));
|
|
3333
3586
|
const download = Command.make("download", {
|
|
3334
|
-
|
|
3587
|
+
document: documentArgument,
|
|
3335
3588
|
server: serverFlag,
|
|
3336
3589
|
output: Flag.string("output").pipe(Flag.withDescription("New file to write the exact HTML bytes to. Existing files are kept.")),
|
|
3337
3590
|
revision: revisionFlag("revision", "Download this historical revision instead of the current one.").pipe(Flag.optional)
|
|
3338
|
-
}, ({
|
|
3591
|
+
}, ({ document, server, output, revision }) => authCommand("download", (signal) => downloadDocument({
|
|
3339
3592
|
server: Option.getOrUndefined(server),
|
|
3340
|
-
|
|
3593
|
+
document,
|
|
3341
3594
|
output,
|
|
3342
3595
|
revisionId: Option.getOrUndefined(revision),
|
|
3343
3596
|
signal
|
|
3344
|
-
}))).pipe(Command.withDescription("Save a document's current or historical HTML to a new file. Visibility is unchanged."));
|
|
3597
|
+
}))).pipe(Command.withDescription("Save a document's current or historical HTML to a new file, by ID or link. Visibility is unchanged."));
|
|
3598
|
+
const read = Command.make("read", {
|
|
3599
|
+
document: documentArgument,
|
|
3600
|
+
server: serverFlag
|
|
3601
|
+
}, ({ document, server }) => {
|
|
3602
|
+
let bytes;
|
|
3603
|
+
return authCommand("read", async (signal) => {
|
|
3604
|
+
const { bytes: read, ...result } = await readDocument({
|
|
3605
|
+
server: Option.getOrUndefined(server),
|
|
3606
|
+
document,
|
|
3607
|
+
signal
|
|
3608
|
+
});
|
|
3609
|
+
bytes = read;
|
|
3610
|
+
return result;
|
|
3611
|
+
}, (result) => bytes ? process.stdout.write(bytes) : console.error(result.message));
|
|
3612
|
+
}).pipe(Command.withDescription("Print a document's current HTML to stdout, by ID or link: your own, a public one or one shared with you. The owner can also read a revision link."));
|
|
3345
3613
|
const visibility = Command.make("visibility", {
|
|
3346
3614
|
documentId: documentIdArgument,
|
|
3347
3615
|
visibility: Argument.choice("visibility", ["private", "public"]),
|
|
@@ -3402,7 +3670,8 @@ function sameCommand(name) {
|
|
|
3402
3670
|
args: rest
|
|
3403
3671
|
};
|
|
3404
3672
|
}
|
|
3405
|
-
|
|
3673
|
+
/** Runs one command and reports its result. `print` replaces the human output of the message. */
|
|
3674
|
+
function authCommand(name, operation, print) {
|
|
3406
3675
|
return Effect.promise(async () => {
|
|
3407
3676
|
const controller = new AbortController();
|
|
3408
3677
|
const interrupt = () => controller.abort();
|
|
@@ -3428,6 +3697,7 @@ function authCommand(name, operation) {
|
|
|
3428
3697
|
console.error(`${name === "status" ? "Could not check status" : name === "skills" ? "Could not install the Pageship skills" : name === "update" ? "Could not update Pageship" : "Pageship request failed"}: ${result.message}`);
|
|
3429
3698
|
return;
|
|
3430
3699
|
}
|
|
3700
|
+
if (print) return print(result);
|
|
3431
3701
|
console.log(result.message);
|
|
3432
3702
|
if (typeof result.verificationUriComplete === "string" && typeof result.userCode === "string" && result.next) console.log(`Open ${result.verificationUriComplete}\nCheck code ${result.userCode}.\nThen run: ${commandLine(result.next.command, result.next.args)}`);
|
|
3433
3703
|
} finally {
|
|
@@ -3436,14 +3706,16 @@ function authCommand(name, operation) {
|
|
|
3436
3706
|
}
|
|
3437
3707
|
});
|
|
3438
3708
|
}
|
|
3439
|
-
const command = Command.make("pageship").pipe(Command.withDescription("Pageship publishes private HTML documents on the hosted Pageship service.\n\nEarly development: check whether this installation is ready with the status command. Authorize this installation with login, then publish one HTML file with publish. Manage published documents with list, history, download, visibility, viewers and restore. Install the Pageship skills for your agents with skills install, and update the CLI with update."), Command.withSubcommands([
|
|
3709
|
+
const command = Command.make("pageship").pipe(Command.withDescription("Pageship publishes private HTML documents on the hosted Pageship service.\n\nEarly development: check whether this installation is ready with the status command. Authorize this installation with login, then publish one HTML file with publish. Sign it out with logout. Manage published documents with list, history, download, visibility, viewers and restore. Read a document you own or were shared, by ID or link, with read. Install the Pageship skills for your agents with skills install, and update the CLI with update."), Command.withSubcommands([
|
|
3440
3710
|
status,
|
|
3441
3711
|
login,
|
|
3442
3712
|
whoami,
|
|
3713
|
+
logoutCommand,
|
|
3443
3714
|
publishCommand,
|
|
3444
3715
|
list,
|
|
3445
3716
|
history,
|
|
3446
3717
|
download,
|
|
3718
|
+
read,
|
|
3447
3719
|
visibility,
|
|
3448
3720
|
viewers,
|
|
3449
3721
|
restore,
|
|
@@ -3451,6 +3723,17 @@ const command = Command.make("pageship").pipe(Command.withDescription("Pageship
|
|
|
3451
3723
|
updateCommand
|
|
3452
3724
|
]), Command.withGlobalFlags([jsonFlag]));
|
|
3453
3725
|
const effectiveArgs = args.every((arg, index) => arg === "--json" || arg.startsWith("--json=") && booleanValue(arg.slice(7)) !== void 0 || index > 0 && args[index - 1] === "--json" && booleanValue(arg) !== void 0) ? [...args, "--help"] : args;
|
|
3726
|
+
/** The subcommand named before `--`, skipping global flags and the values they take. */
|
|
3727
|
+
function subcommandName() {
|
|
3728
|
+
for (let index = 0; index < flagArgs.length; index++) {
|
|
3729
|
+
const arg = flagArgs[index];
|
|
3730
|
+
if (arg === "--json" && booleanValue(flagArgs[index + 1]) !== void 0) index++;
|
|
3731
|
+
else if (arg === "--log-level" || arg === "--completions") index++;
|
|
3732
|
+
else if (!arg.startsWith("-")) return arg;
|
|
3733
|
+
}
|
|
3734
|
+
}
|
|
3735
|
+
const builtInFlag = /^(?:--help|-h|--version|-v|--completions|--wizard)(?:=|$)/u;
|
|
3736
|
+
const readsDocument = !json && subcommandName() === "read" && !flagArgs.some((arg) => builtInFlag.test(arg));
|
|
3454
3737
|
const program = Command.runWith(command, {
|
|
3455
3738
|
version,
|
|
3456
3739
|
renderErrors: !json
|
|
@@ -3475,7 +3758,10 @@ await Effect.runPromise(json ? program.pipe(Effect.provideService(CliOutput.Form
|
|
|
3475
3758
|
...console,
|
|
3476
3759
|
log: () => {},
|
|
3477
3760
|
error: () => {}
|
|
3478
|
-
}), Effect.provide(CliConfig.layer({ builtIns: [GlobalFlag.Help, GlobalFlag.Version] }))) : program
|
|
3761
|
+
}), Effect.provide(CliConfig.layer({ builtIns: [GlobalFlag.Help, GlobalFlag.Version] }))) : readsDocument ? program.pipe(Effect.provideService(Console.Console, {
|
|
3762
|
+
...console,
|
|
3763
|
+
log: console.error
|
|
3764
|
+
})) : program);
|
|
3479
3765
|
if (json) {
|
|
3480
3766
|
if (!envelope) settle(null, {
|
|
3481
3767
|
status: "internal_error",
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pageship
|
|
3
|
-
description: Publish an HTML file to Pageship and manage what is published. Use when the user asks to publish, share or get a link to a document, update its published copy, change its visibility or viewers, list, inspect history, download or restore published documents, or sign in to Pageship. To write, edit, rename or move a document, load pageship-docs instead.
|
|
3
|
+
description: Publish an HTML file to Pageship, read Pageship documents and manage what is published. Use when the user pastes or names a Pageship document link (https://<workspace>.pageship.dev/d/<id>, not a link to the pageship.dev site, the dashboard or the API), or asks to publish, share or get a link to a document, update its published copy, change its visibility or viewers, list, inspect history, download or restore published documents, or sign in to or out of Pageship. To write, edit, rename or move a document, load pageship-docs instead.
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.7.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Pageship
|
|
@@ -91,6 +91,16 @@ On `reauthentication_required`, ask the user to sign in to the Pageship dashboar
|
|
|
91
91
|
|
|
92
92
|
When `login` returns `cancelled`, `interrupted` or `request_failed` with a `user`, authorization succeeded and the credential is kept, but no address is selected. Run the returned `next` when the user is ready.
|
|
93
93
|
|
|
94
|
+
## Sign out
|
|
95
|
+
|
|
96
|
+
Only when the user asks to sign this installation out of Pageship, run:
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
pageship --json logout
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
On `logged_out`, the installation is signed out and its credential is deleted. `revoked: false` means there was nothing to revoke, which also counts as signed out. Report the `message` either way: it can ask the user to revoke a leftover session in the dashboard. On any other status, report the `message`, which says whether the installation is still signed in. Run the returned `next`, when there is one, only when the user wants to retry.
|
|
103
|
+
|
|
94
104
|
## Publish
|
|
95
105
|
|
|
96
106
|
Set the shell placeholder `PAGESHIP_FILE` to one nonempty `.html` or `.htm` file. Pageship uses the server's configured per-file size limit. A new document is private. An existing source-path match does not overwrite a document.
|
|
@@ -141,6 +151,10 @@ When the user names the people to share it with, keep it private and add them as
|
|
|
141
151
|
|
|
142
152
|
When the user names no one and the result is private, ask whether to make it public, and say in the question that anyone with the link can then read it. Mention that it can instead stay private and be shared with named GitHub users. When it is already public, because the user made it public earlier, say so and don't ask. Change visibility only after the user agrees, as in [visibility](references/visibility.md).
|
|
143
153
|
|
|
154
|
+
## Read a document link
|
|
155
|
+
|
|
156
|
+
A document link is `https://<workspace>.pageship.dev/d/<id>`, often followed by `-<slug>` and sometimes by `/revisions/<revisionId>`. When the user pastes one or asks about one, read it with `pageship read`, as in [read](references/read.md), instead of fetching it: a private document's link answers a fetch like a missing page, and `read` also reads public documents. Fetch a document link only when the CLI isn't installed or the user doesn't want to sign in; that works for public documents alone. Links to `pageship.dev` itself, `app.pageship.dev` or `api.pageship.dev` are not document links; fetch or open them as usual.
|
|
157
|
+
|
|
144
158
|
## Use another server
|
|
145
159
|
|
|
146
160
|
The CLI uses the hosted Pageship service by default. Only when the user names another Pageship server, such as a local development server, add `--server <origin>` to every command you start yourself. Returned `next` and `resolutions` arguments already carry that server, so run them unchanged.
|
|
@@ -150,12 +164,13 @@ The CLI uses the hosted Pageship service by default. Only when the user names an
|
|
|
150
164
|
Load the reference for the task:
|
|
151
165
|
|
|
152
166
|
- [List and history](references/list-and-history.md): find a document's `id`, `visibility`, current `revisionId` and `url`, and inspect its revisions.
|
|
153
|
-
- [
|
|
167
|
+
- [Read](references/read.md): print a document's current HTML, by its ID or the link the user pasted, for a document the user owns, a public one, or one the user was added to as a viewer.
|
|
168
|
+
- [Download](references/download.md): save a document's HTML to a file, current or from an earlier revision, by its ID or the link the user pasted.
|
|
154
169
|
- [Visibility](references/visibility.md): make a document public or private.
|
|
155
170
|
- [Viewers](references/viewers.md): list, add or remove the GitHub users who can read a private document.
|
|
156
171
|
- [Restore](references/restore.md): make an earlier revision current again.
|
|
157
172
|
|
|
158
|
-
Deleting a document, recovering a deleted one, changing a document's display title and revoking
|
|
173
|
+
Deleting a document, recovering a deleted one, changing a document's display title and revoking another CLI installation happen in the dashboard, at https://app.pageship.dev for the hosted service. The CLI has no commands for them yet, so give the user the dashboard link.
|
|
159
174
|
|
|
160
175
|
## Handle other outcomes
|
|
161
176
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# Download
|
|
2
2
|
|
|
3
|
-
To
|
|
3
|
+
To save a document's HTML to a file, run:
|
|
4
4
|
|
|
5
5
|
```sh
|
|
6
6
|
pageship --json download "$PAGESHIP_DOCUMENT" --output "$PAGESHIP_OUTPUT"
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
Set `PAGESHIP_DOCUMENT` to the document's `id` from `list`,
|
|
9
|
+
Set `PAGESHIP_DOCUMENT` to the document's `id` from `list`, or to the document link the user pasted, such as `https://<workspace>.pageship.dev/d/<id>-<slug>`; you don't need `list` to find the ID. Set `PAGESHIP_OUTPUT` to a path that does not exist. For a historical revision, add `--revision <revisionId>` with an ID from `history`, or pass the revision link, which ends in `/revisions/<revisionId>`. On `invalid_document`, the value is not a Pageship document link; ask the user for the right link or ID. The bytes go only to that file. On `output_exists`, nothing was written or replaced; choose another path. A download never changes the document or its visibility. For another person's document, public or shared with the user, download gets the current revision only. To read HTML without writing a file, use [read](read.md).
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# Read
|
|
2
|
+
|
|
3
|
+
To read a document's HTML, run:
|
|
4
|
+
|
|
5
|
+
```sh
|
|
6
|
+
pageship --json read "$PAGESHIP_DOCUMENT"
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Set `PAGESHIP_DOCUMENT` to the document link the user pasted, such as `https://<workspace>.pageship.dev/d/<id>-<slug>`, or to the document's `id` from `list`. On `read`, the document's HTML is in `html`, and `revisionId` is `null` for the current revision. Without `--json`, the command prints the HTML alone on standard output, so you can redirect it to a file.
|
|
10
|
+
|
|
11
|
+
Reading works for any public document, and for a private document's owner and its viewers, the GitHub accounts the owner shared it with, signed in to this installation. The owner can also pass a revision link, which ends in `/revisions/<revisionId>`, to read that revision; a viewer reads the current revision only.
|
|
12
|
+
|
|
13
|
+
- `invalid_document`: the value isn't a document link. Links to the pageship.dev site, the dashboard and the API are refused before any request. Fetch or open those as usual.
|
|
14
|
+
- `unavailable`: the document doesn't exist, was deleted, or the signed-in account can't read it. Pageship doesn't say which. Tell the user, and ask them to check the link and which GitHub account they signed in with; `pageship --json whoami` shows it. Someone who should have access needs the owner to add their account as a viewer.
|
|
15
|
+
- `signed_out`: sign in as [Sign in](../SKILL.md#sign-in) describes, then read again.
|
|
16
|
+
|
|
17
|
+
Reading never changes the document, and doesn't count as a view.
|
|
@@ -3,7 +3,7 @@ name: pageship-chart
|
|
|
3
3
|
description: "Later step of pageship-docs: for a request to write or edit a document, load pageship-docs first; load this skill first only when the user names it. Pattern for charts in a Pageship HTML document, loaded by a pageship- kind skill before it draws a chart."
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.7.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Chart
|
|
@@ -3,7 +3,7 @@ name: pageship-code-block
|
|
|
3
3
|
description: "Later step of pageship-docs: for a request to write or edit a document, load pageship-docs first; load this skill first only when the user names it. Pattern for code in a Pageship HTML document, such as source code, commands, configuration or logs, loaded by a pageship- kind skill before the first code block."
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.7.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Code block
|
|
@@ -3,7 +3,7 @@ name: pageship-decision-record
|
|
|
3
3
|
description: HTML decision records, as the second step of pageship-docs. For any request to record, write, regenerate, edit or move a decision, load pageship-docs first; load this skill first only when the user names it.
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.7.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Decision record
|
|
@@ -3,7 +3,7 @@ name: pageship-diagram
|
|
|
3
3
|
description: "Later step of pageship-docs: for a request to write or edit a document, load pageship-docs first; load this skill first only when the user names it. Pattern for diagrams in a Pageship HTML document, such as a process, a timeline, a system map or states, loaded by a pageship- kind skill before it draws a diagram."
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.7.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Diagram
|
|
@@ -3,7 +3,7 @@ name: pageship-docs
|
|
|
3
3
|
description: First step for any document people read, such as a report, plan, spec, explainer, review, decision record or slide deck, in HTML or Markdown. Load it before any other pageship- skill. Use when the user asks for one of these documents, asks to regenerate, redesign, edit, rename, move or copy an HTML source file, or asks to record whether they want HTML or Markdown.
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.7.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Pageship documents
|
|
@@ -3,7 +3,7 @@ name: pageship-explainer
|
|
|
3
3
|
description: HTML explainers, as the second step of pageship-docs. For any request to explain how something works, or to write, regenerate, edit or move an explainer, load pageship-docs first; load this skill first only when the user names it.
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.7.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Explainer
|
|
@@ -3,7 +3,7 @@ name: pageship-interaction
|
|
|
3
3
|
description: "Later step of pageship-docs: for a request to write or edit a document, load pageship-docs first; load this skill first only when the user names it. Pattern for controls in a Pageship HTML document, such as stepping through stages, tracing a path, tabs, filters, revealing detail and pointer states on charts and diagrams, loaded by a pageship- kind skill before it adds any control."
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.7.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Interaction
|
|
@@ -3,7 +3,7 @@ name: pageship-key-figures
|
|
|
3
3
|
description: "Later step of pageship-docs: for a request to write or edit a document, load pageship-docs first; load this skill first only when the user names it. Pattern for the few numbers and callouts a Pageship HTML document opens with, loaded by a pageship- kind skill before it writes key figures."
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.7.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Key figures
|
|
@@ -3,7 +3,7 @@ name: pageship-media
|
|
|
3
3
|
description: "Later step of pageship-docs: for a request to write or edit a document, load pageship-docs first; load this skill first only when the user names it. Pattern for images, video and audio in a Pageship HTML document, loaded by a pageship- kind skill before it shows media."
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.7.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Media
|
|
@@ -3,7 +3,7 @@ name: pageship-motion
|
|
|
3
3
|
description: "Later step of pageship-docs: for a request to write or edit a document, load pageship-docs first; load this skill first only when the user names it. Pattern for animation and transitions in a Pageship HTML document, such as a chart that grows into view, a sequence that plays through a diagram, or a marker moving along a path, loaded by a pageship- kind skill before it draws a chart, a graphic or a sequence, or before anything else on the page moves."
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.7.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Motion
|
|
@@ -3,7 +3,7 @@ name: pageship-plan
|
|
|
3
3
|
description: HTML plans, as the second step of pageship-docs. For any request to write, regenerate, edit or move a plan, load pageship-docs first; load this skill first only when the user names it.
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.7.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Plan
|
|
@@ -3,7 +3,7 @@ name: pageship-report
|
|
|
3
3
|
description: HTML reports, as the second step of pageship-docs. For any request to write, regenerate, edit or move a report, load pageship-docs first; load this skill first only when the user names it.
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.7.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Report
|
|
@@ -3,7 +3,7 @@ name: pageship-review-report
|
|
|
3
3
|
description: HTML review reports, as the second step of pageship-docs. For any request to review a change or a plan and write up the findings, or to write, regenerate, edit or move a review report, load pageship-docs first; load this skill first only when the user names it.
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.7.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Review report
|
|
@@ -3,7 +3,7 @@ name: pageship-slide-deck
|
|
|
3
3
|
description: HTML slide decks, as the second step of pageship-docs. For any request to make slides or a presentation, or to regenerate, edit or move a deck, load pageship-docs first; load this skill first only when the user names it.
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.7.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Slide deck
|
|
@@ -3,7 +3,7 @@ name: pageship-spec
|
|
|
3
3
|
description: HTML specs, as the second step of pageship-docs. For any request to write, regenerate, edit or move a spec, load pageship-docs first; load this skill first only when the user names it.
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.7.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Spec
|
|
@@ -3,7 +3,7 @@ name: pageship-table
|
|
|
3
3
|
description: "Later step of pageship-docs: for a request to write or edit a document, load pageship-docs first; load this skill first only when the user names it. Pattern for tables in a Pageship HTML document, loaded by a pageship- kind skill before it writes a table."
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.7.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Table
|