pageship 0.4.1 → 0.5.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/dist/cli.mjs +306 -18
- package/dist/skills/pageship/SKILL.md +9 -4
- package/dist/skills/pageship/references/viewers.md +43 -0
- package/dist/skills/pageship/references/visibility.md +2 -2
- package/dist/skills/pageship-chart/SKILL.md +2 -2
- package/dist/skills/pageship-code-block/SKILL.md +2 -2
- package/dist/skills/pageship-decision-record/SKILL.md +1 -1
- package/dist/skills/pageship-diagram/SKILL.md +2 -2
- 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 +2 -2
- package/dist/skills/pageship-key-figures/SKILL.md +2 -2
- package/dist/skills/pageship-media/SKILL.md +2 -2
- package/dist/skills/pageship-motion/SKILL.md +2 -2
- 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 +2 -2
- package/package.json +1 -1
package/dist/cli.mjs
CHANGED
|
@@ -683,6 +683,26 @@ const documentsUpdateVisibility = (options) => (options.client ?? client).patch(
|
|
|
683
683
|
...options.headers
|
|
684
684
|
}
|
|
685
685
|
});
|
|
686
|
+
const viewersList = (options) => (options.client ?? client).get({
|
|
687
|
+
url: "/api/v1/documents/{id}/viewers",
|
|
688
|
+
...options
|
|
689
|
+
});
|
|
690
|
+
const viewersAdd = (options) => (options.client ?? client).post({
|
|
691
|
+
url: "/api/v1/documents/{id}/viewers",
|
|
692
|
+
...options,
|
|
693
|
+
headers: {
|
|
694
|
+
"Content-Type": "application/json",
|
|
695
|
+
...options.headers
|
|
696
|
+
}
|
|
697
|
+
});
|
|
698
|
+
const viewersRemove = (options) => (options.client ?? client).delete({
|
|
699
|
+
url: "/api/v1/documents/{id}/viewers/{githubAccountId}",
|
|
700
|
+
...options
|
|
701
|
+
});
|
|
702
|
+
const githubGetUser = (options) => (options.client ?? client).get({
|
|
703
|
+
url: "/api/v1/github/users/{login}",
|
|
704
|
+
...options
|
|
705
|
+
});
|
|
686
706
|
//#endregion
|
|
687
707
|
//#region ../../packages/api-client/src/generated/workspace-domain.gen.ts
|
|
688
708
|
/** Every workspace address and document URL is a subdomain of this domain. */
|
|
@@ -760,14 +780,16 @@ function validTitle(value) {
|
|
|
760
780
|
}
|
|
761
781
|
function normalizeDocument(value) {
|
|
762
782
|
if (!record(value) || typeof value.slug !== "string") return;
|
|
763
|
-
const normalized =
|
|
783
|
+
const normalized = {
|
|
764
784
|
...value,
|
|
765
|
-
title: value.slug
|
|
766
|
-
|
|
785
|
+
...value.title === void 0 ? { title: value.slug } : {},
|
|
786
|
+
...value.viewCount === void 0 ? { viewCount: 0 } : {},
|
|
787
|
+
...value.sharedWith === void 0 ? { sharedWith: 0 } : {}
|
|
788
|
+
};
|
|
767
789
|
return validDocument(normalized) ? normalized : void 0;
|
|
768
790
|
}
|
|
769
791
|
function validDocument(value) {
|
|
770
|
-
return record(value) && isDocumentId(value.id) && typeof value.slug === "string" && /^[a-z0-9]+(?:-[a-z0-9]+)*(?![\s\S])/u.test(value.slug) && validTitle(value.title) && typeof value.sourcePath === "string" && value.sourcePath.length <= 1024 && /^(?!\/)(?!.*(?:^|\/)\.{1,2}(?:\/|$))(?!.*\/\/)[^\x00-\x1f\x7f\\:]*\.[hH][tT][mM][lL]?(?![\s\S])/u.test(value.sourcePath) && (value.repository === null || isRepository(value.repository)) && (value.visibility === "private" || value.visibility === "public") && isRevisionId(value.revisionId) && typeof value.byteLength === "number" && Number.isSafeInteger(value.byteLength) && value.byteLength > 0 && typeof value.createdAt === "number" && Number.isSafeInteger(value.createdAt) && value.createdAt >= 0 && typeof value.publishedAt === "number" && Number.isSafeInteger(value.publishedAt) && value.publishedAt >= 0 && typeof value.url === "string" && new RegExp(`^https://[a-z0-9-]+\\.${workspaceDomainPattern}/d/${value.id}-${value.slug}$`, "u").test(value.url);
|
|
792
|
+
return record(value) && isDocumentId(value.id) && typeof value.slug === "string" && /^[a-z0-9]+(?:-[a-z0-9]+)*(?![\s\S])/u.test(value.slug) && validTitle(value.title) && typeof value.sourcePath === "string" && value.sourcePath.length <= 1024 && /^(?!\/)(?!.*(?:^|\/)\.{1,2}(?:\/|$))(?!.*\/\/)[^\x00-\x1f\x7f\\:]*\.[hH][tT][mM][lL]?(?![\s\S])/u.test(value.sourcePath) && (value.repository === null || isRepository(value.repository)) && (value.visibility === "private" || value.visibility === "public") && isRevisionId(value.revisionId) && typeof value.byteLength === "number" && Number.isSafeInteger(value.byteLength) && value.byteLength > 0 && typeof value.createdAt === "number" && Number.isSafeInteger(value.createdAt) && value.createdAt >= 0 && typeof value.publishedAt === "number" && Number.isSafeInteger(value.publishedAt) && value.publishedAt >= 0 && typeof value.viewCount === "number" && Number.isSafeInteger(value.viewCount) && value.viewCount >= 0 && typeof value.sharedWith === "number" && Number.isSafeInteger(value.sharedWith) && value.sharedWith >= 0 && typeof value.url === "string" && new RegExp(`^https://[a-z0-9-]+\\.${workspaceDomainPattern}/d/${value.id}-${value.slug}$`, "u").test(value.url);
|
|
771
793
|
}
|
|
772
794
|
function validRevision(value, documentId) {
|
|
773
795
|
return record(value) && isRevisionId(value.id) && typeof value.createdAt === "number" && Number.isSafeInteger(value.createdAt) && value.createdAt >= 0 && typeof value.byteLength === "number" && Number.isSafeInteger(value.byteLength) && value.byteLength > 0 && typeof value.isCurrent === "boolean" && (value.cliVersion === null || isCliVersion(value.cliVersion)) && typeof value.url === "string" && new RegExp(`^https://[a-z0-9-]+\\.${workspaceDomainPattern}/d/${documentId}-[a-z0-9]+(?:-[a-z0-9]+)*/revisions/${value.id}$`, "u").test(value.url);
|
|
@@ -913,9 +935,12 @@ async function updateDocumentVisibility(baseUrl, id, visibility, options = {}) {
|
|
|
913
935
|
throw new Error("Could not update document visibility. Try again.", { cause: error });
|
|
914
936
|
}
|
|
915
937
|
const data = received;
|
|
916
|
-
|
|
938
|
+
const updated = record(data) && data.status === "visibility_updated" ? normalizeDocument(data.document) : void 0;
|
|
939
|
+
const removedViewers = record(data) && data.removedViewers !== void 0 ? data.removedViewers : 0;
|
|
940
|
+
if (updated?.visibility === visibility && typeof removedViewers === "number" && Number.isSafeInteger(removedViewers) && removedViewers >= 0) return {
|
|
917
941
|
status: "visibility_updated",
|
|
918
|
-
document:
|
|
942
|
+
document: updated,
|
|
943
|
+
removedViewers
|
|
919
944
|
};
|
|
920
945
|
throw new Error("Invalid document visibility response.");
|
|
921
946
|
}
|
|
@@ -957,6 +982,92 @@ async function publishDocument(baseUrl, input, options = {}) {
|
|
|
957
982
|
if (record(data) && (data.status === "idempotency_conflict" || data.status === "address_required" || data.status === "unavailable" || data.status === "document_id_taken")) return { status: data.status };
|
|
958
983
|
throw new Error("Invalid publication response. Retry with the same idempotency key.");
|
|
959
984
|
}
|
|
985
|
+
/** Same GitHub username grammar as the Effect contract. */
|
|
986
|
+
function isGitHubLogin(value) {
|
|
987
|
+
return typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9-]{0,38}(?![\s\S])/u.test(value);
|
|
988
|
+
}
|
|
989
|
+
function isGitHubAccountId(value) {
|
|
990
|
+
return typeof value === "string" && /^[1-9][0-9]{0,19}(?![\s\S])/u.test(value);
|
|
991
|
+
}
|
|
992
|
+
function validViewer(value) {
|
|
993
|
+
return record(value) && isGitHubAccountId(value.githubAccountId) && isGitHubLogin(value.login) && (value.name === null || typeof value.name === "string") && typeof value.addedAt === "number" && Number.isSafeInteger(value.addedAt) && value.addedAt >= 0;
|
|
994
|
+
}
|
|
995
|
+
function validUserMatch(value) {
|
|
996
|
+
return record(value) && isGitHubAccountId(value.githubAccountId) && isGitHubLogin(value.login);
|
|
997
|
+
}
|
|
998
|
+
function validUserProfile(value) {
|
|
999
|
+
return record(value) && (value.name === null || typeof value.name === "string") && (value.type === "user" || value.type === "organization" || value.type === "other") && validUserMatch(value);
|
|
1000
|
+
}
|
|
1001
|
+
/**
|
|
1002
|
+
* One message per viewer refusal. The body's status picks it, not the HTTP code: a refused
|
|
1003
|
+
* GitHub token and a signed-out session are both 401.
|
|
1004
|
+
*/
|
|
1005
|
+
const viewerRefusals = {
|
|
1006
|
+
signed_out: "Sign in to manage viewers.",
|
|
1007
|
+
uninvited: "Access unavailable.",
|
|
1008
|
+
forbidden: "A trusted browser origin is required.",
|
|
1009
|
+
unavailable: "Document unavailable.",
|
|
1010
|
+
document_public: "Make the document private before adding viewers.",
|
|
1011
|
+
github_user_not_found: "GitHub has no user with that username.",
|
|
1012
|
+
github_account_mismatch: "That username now belongs to a different GitHub account. Look it up again.",
|
|
1013
|
+
not_personal_account: "Only a personal GitHub account can be a viewer.",
|
|
1014
|
+
owner_account: "You already have access to your own document.",
|
|
1015
|
+
github_sign_in_required: "GitHub refused your sign-in. Sign in to Pageship again.",
|
|
1016
|
+
github_rate_limited: "GitHub is limiting requests. Try again in a minute.",
|
|
1017
|
+
github_unavailable: "GitHub is unavailable. Try again."
|
|
1018
|
+
};
|
|
1019
|
+
function isViewerRefusal(value) {
|
|
1020
|
+
return typeof value === "string" && Object.hasOwn(viewerRefusals, value);
|
|
1021
|
+
}
|
|
1022
|
+
function viewerFailed(response, error) {
|
|
1023
|
+
if (response && record(error) && isViewerRefusal(error.status)) throw new DocumentRequestError(error.status, viewerRefusals[error.status], response.status);
|
|
1024
|
+
failed(response, error);
|
|
1025
|
+
}
|
|
1026
|
+
async function getDocumentViewers(baseUrl, id, options = {}) {
|
|
1027
|
+
const { data, response, error } = await viewersList({
|
|
1028
|
+
...requestOptions(baseUrl, options),
|
|
1029
|
+
path: { id }
|
|
1030
|
+
});
|
|
1031
|
+
if (!response?.ok) viewerFailed(response, error);
|
|
1032
|
+
if (data?.status === "listed" && Array.isArray(data.viewers) && data.viewers.every(validViewer)) return data;
|
|
1033
|
+
throw new Error("Invalid document viewer listing response.");
|
|
1034
|
+
}
|
|
1035
|
+
/** Adds the account the owner confirmed. The server looks the login up again before adding it. */
|
|
1036
|
+
async function addDocumentViewer(baseUrl, id, user, options = {}) {
|
|
1037
|
+
const { data, response, error } = await viewersAdd({
|
|
1038
|
+
...changeOptions(baseUrl, options),
|
|
1039
|
+
path: { id },
|
|
1040
|
+
body: {
|
|
1041
|
+
githubAccountId: user.githubAccountId,
|
|
1042
|
+
login: user.login
|
|
1043
|
+
}
|
|
1044
|
+
});
|
|
1045
|
+
if (!response?.ok) viewerFailed(response, error);
|
|
1046
|
+
if (data?.status === "added" && validViewer(data.viewer) && data.viewer.githubAccountId === user.githubAccountId) return data;
|
|
1047
|
+
throw new Error("Invalid document viewer response.");
|
|
1048
|
+
}
|
|
1049
|
+
/** Removing an account that isn't a viewer succeeds. */
|
|
1050
|
+
async function removeDocumentViewer(baseUrl, id, githubAccountId, options = {}) {
|
|
1051
|
+
const { data, response, error } = await viewersRemove({
|
|
1052
|
+
...changeOptions(baseUrl, options),
|
|
1053
|
+
path: {
|
|
1054
|
+
id,
|
|
1055
|
+
githubAccountId
|
|
1056
|
+
}
|
|
1057
|
+
});
|
|
1058
|
+
if (!response?.ok) viewerFailed(response, error);
|
|
1059
|
+
if (data?.status === "removed") return { status: "removed" };
|
|
1060
|
+
throw new Error("Invalid document viewer removal response.");
|
|
1061
|
+
}
|
|
1062
|
+
async function getGitHubUser(baseUrl, login, options = {}) {
|
|
1063
|
+
const { data, response, error } = await githubGetUser({
|
|
1064
|
+
...requestOptions(baseUrl, options),
|
|
1065
|
+
path: { login }
|
|
1066
|
+
});
|
|
1067
|
+
if (!response?.ok) viewerFailed(response, error);
|
|
1068
|
+
if (data?.status === "found" && validUserProfile(data.user)) return data;
|
|
1069
|
+
throw new Error("Invalid GitHub user response.");
|
|
1070
|
+
}
|
|
960
1071
|
//#endregion
|
|
961
1072
|
//#region ../../packages/api-client/src/index.ts
|
|
962
1073
|
async function getWorkspace(baseUrl, options = {}) {
|
|
@@ -971,7 +1082,17 @@ async function getWorkspace(baseUrl, options = {}) {
|
|
|
971
1082
|
throwOnError: false
|
|
972
1083
|
});
|
|
973
1084
|
if (!response?.ok) throw new Error("Could not load your workspace.", { cause: error });
|
|
974
|
-
if (data?.status === "signed_out"
|
|
1085
|
+
if (data?.status === "signed_out") return { status: data.status };
|
|
1086
|
+
if (data?.status === "uninvited") {
|
|
1087
|
+
const user = data.user;
|
|
1088
|
+
return user && typeof user.name === "string" && (user.login === void 0 || typeof user.login === "string") ? {
|
|
1089
|
+
status: data.status,
|
|
1090
|
+
user: {
|
|
1091
|
+
name: user.name,
|
|
1092
|
+
...user.login ? { login: user.login } : {}
|
|
1093
|
+
}
|
|
1094
|
+
} : { status: data.status };
|
|
1095
|
+
}
|
|
975
1096
|
if (data?.status === "admitted" && typeof data.user?.id === "string" && data.user.id.length > 0 && typeof data.user?.name === "string" && (data.user.login === void 0 || typeof data.user.login === "string") && (data.user.githubAccountId === void 0 || typeof data.user.githubAccountId === "string" && /^[1-9]\d*$/u.test(data.user.githubAccountId)) && typeof data.workspace?.id === "string" && data.workspace.id.length > 0 && (data.address === void 0 || data.address === null || isWorkspaceAddress(data.address))) return data;
|
|
976
1097
|
throw new Error("Invalid workspace response.");
|
|
977
1098
|
}
|
|
@@ -1325,6 +1446,7 @@ const outcomes = {
|
|
|
1325
1446
|
downloaded: "succeeded",
|
|
1326
1447
|
visibility_updated: "succeeded",
|
|
1327
1448
|
restored: "succeeded",
|
|
1449
|
+
viewers_updated: "succeeded",
|
|
1328
1450
|
skills_installed: "succeeded",
|
|
1329
1451
|
authorization_pending: "pending",
|
|
1330
1452
|
expired: "pending",
|
|
@@ -1336,6 +1458,7 @@ const outcomes = {
|
|
|
1336
1458
|
repository_mismatch: "pending",
|
|
1337
1459
|
marker_unavailable: "pending",
|
|
1338
1460
|
revision_conflict: "pending",
|
|
1461
|
+
github_sign_in_required: "pending",
|
|
1339
1462
|
cancelled: "pending",
|
|
1340
1463
|
usage_error: "failed",
|
|
1341
1464
|
internal_error: "failed",
|
|
@@ -1359,7 +1482,15 @@ const outcomes = {
|
|
|
1359
1482
|
idempotency_conflict: "failed",
|
|
1360
1483
|
document_id_taken: "failed",
|
|
1361
1484
|
publication_action_unsupported: "failed",
|
|
1362
|
-
skills_modified: "failed"
|
|
1485
|
+
skills_modified: "failed",
|
|
1486
|
+
ambiguous_viewer: "failed",
|
|
1487
|
+
document_public: "failed",
|
|
1488
|
+
github_user_not_found: "failed",
|
|
1489
|
+
github_account_mismatch: "failed",
|
|
1490
|
+
not_personal_account: "failed",
|
|
1491
|
+
owner_account: "failed",
|
|
1492
|
+
github_rate_limited: "failed",
|
|
1493
|
+
github_unavailable: "failed"
|
|
1363
1494
|
};
|
|
1364
1495
|
const isStatus = (value) => Object.hasOwn(outcomes, value);
|
|
1365
1496
|
const commandNames = [
|
|
@@ -1371,6 +1502,7 @@ const commandNames = [
|
|
|
1371
1502
|
"history",
|
|
1372
1503
|
"download",
|
|
1373
1504
|
"visibility",
|
|
1505
|
+
"viewers",
|
|
1374
1506
|
"restore",
|
|
1375
1507
|
"skills"
|
|
1376
1508
|
];
|
|
@@ -1422,7 +1554,7 @@ function commandLine(command, args) {
|
|
|
1422
1554
|
}
|
|
1423
1555
|
//#endregion
|
|
1424
1556
|
//#region package.json
|
|
1425
|
-
var version = "0.
|
|
1557
|
+
var version = "0.5.0";
|
|
1426
1558
|
//#endregion
|
|
1427
1559
|
//#region src/publish.ts
|
|
1428
1560
|
const execute = promisify(execFile);
|
|
@@ -2142,6 +2274,25 @@ async function identify(serverValue, signal) {
|
|
|
2142
2274
|
}
|
|
2143
2275
|
//#endregion
|
|
2144
2276
|
//#region src/documents.ts
|
|
2277
|
+
/** `1 viewer`, `2 viewers`. */
|
|
2278
|
+
const viewerCount = (count) => `${count} viewer${count === 1 ? "" : "s"}`;
|
|
2279
|
+
/** The result for a request the server refused. `login` signs in again. */
|
|
2280
|
+
function refusal(error, login) {
|
|
2281
|
+
const status = error.status;
|
|
2282
|
+
if (status === "signed_out") return {
|
|
2283
|
+
status,
|
|
2284
|
+
message: `Your credential was revoked, expired or is invalid. Run ${commandLine(login.command, login.args)} to sign in again.`,
|
|
2285
|
+
next: login
|
|
2286
|
+
};
|
|
2287
|
+
if (status === "uninvited") return {
|
|
2288
|
+
status,
|
|
2289
|
+
message: "This account is not invited. Contact the server owner."
|
|
2290
|
+
};
|
|
2291
|
+
return {
|
|
2292
|
+
status,
|
|
2293
|
+
message: error.message
|
|
2294
|
+
};
|
|
2295
|
+
}
|
|
2145
2296
|
/** Checks compatibility and the stored credential; the server enforces ownership and admission. */
|
|
2146
2297
|
async function asOwner(serverValue, signal, operation) {
|
|
2147
2298
|
const selection = selectServer(serverValue);
|
|
@@ -2174,14 +2325,11 @@ async function asOwner(serverValue, signal, operation) {
|
|
|
2174
2325
|
signal
|
|
2175
2326
|
});
|
|
2176
2327
|
} catch (error) {
|
|
2177
|
-
if (!(error
|
|
2178
|
-
return
|
|
2179
|
-
status: error.status,
|
|
2180
|
-
message: error.status === "signed_out" ? `Your credential was revoked, expired or is invalid. Run ${login} to sign in again.` : error.status === "uninvited" ? "This account is not invited. Contact the server owner." : error.message,
|
|
2181
|
-
...error.status === "signed_out" ? { next } : {}
|
|
2182
|
-
};
|
|
2328
|
+
if (!isRefusal(error)) throw error;
|
|
2329
|
+
return refusal(error, next);
|
|
2183
2330
|
}
|
|
2184
2331
|
}
|
|
2332
|
+
const isRefusal = (error) => error instanceof DocumentRequestError && isStatus(error.status);
|
|
2185
2333
|
function listDocuments(options) {
|
|
2186
2334
|
return asOwner(options.server, options.signal, async ({ origin, args }, request) => {
|
|
2187
2335
|
const page = await getDocuments(origin, {
|
|
@@ -2201,7 +2349,7 @@ function listDocuments(options) {
|
|
|
2201
2349
|
...next ? { next } : {},
|
|
2202
2350
|
message: [
|
|
2203
2351
|
page.documents.length ? "Documents:" : options.cursor ? "No more documents." : "No documents.",
|
|
2204
|
-
...page.documents.map((document) => `${document.id} ${document.visibility} ${document.title}\n` + (document.repository ? ` repository ${document.repository}\n` : "") + ` source ${document.sourcePath}\n current revision ${document.revisionId}\n ${document.url}`),
|
|
2352
|
+
...page.documents.map((document) => `${document.id} ${document.visibility} ${viewerCount(document.sharedWith)} ${document.title}\n` + (document.repository ? ` repository ${document.repository}\n` : "") + ` source ${document.sourcePath}\n current revision ${document.revisionId}\n ${document.url}`),
|
|
2205
2353
|
...next ? [`More documents: run ${commandLine(next.command, next.args)}`] : []
|
|
2206
2354
|
].join("\n")
|
|
2207
2355
|
};
|
|
@@ -2280,9 +2428,10 @@ function downloadDocument(options) {
|
|
|
2280
2428
|
function changeVisibility(options) {
|
|
2281
2429
|
return asOwner(options.server, options.signal, async ({ origin }, request) => {
|
|
2282
2430
|
const result = await updateDocumentVisibility(origin, options.documentId, options.visibility, request);
|
|
2431
|
+
const { document, removedViewers } = result;
|
|
2283
2432
|
return {
|
|
2284
2433
|
...result,
|
|
2285
|
-
message:
|
|
2434
|
+
message: document.visibility === "public" ? `${document.id} is public.${removedViewers ? ` Removed its ${viewerCount(removedViewers)}.` : ""} Anyone with the URL can read its current revision: ${document.url}` : `${document.id} is private. Only you and its ${document.sharedWith ? viewerCount(document.sharedWith) : "viewers"} can read it after signing in: ${document.url}`
|
|
2286
2435
|
};
|
|
2287
2436
|
});
|
|
2288
2437
|
}
|
|
@@ -2752,6 +2901,132 @@ async function checkReadiness(serverValue, signal) {
|
|
|
2752
2901
|
};
|
|
2753
2902
|
}
|
|
2754
2903
|
//#endregion
|
|
2904
|
+
//#region src/viewers.ts
|
|
2905
|
+
/** `octocat (Mona Lisa), GitHub ID 583231` */
|
|
2906
|
+
const account = ({ login, name, githubAccountId }) => `${login}${name ? ` (${name})` : ""}, GitHub ID ${githubAccountId}`;
|
|
2907
|
+
function viewerList(documentId, viewers) {
|
|
2908
|
+
return viewers.length ? [`Viewers of ${documentId}:`, ...viewers.map((viewer) => ` ${account(viewer)}`)].join("\n") : `${documentId} has no viewers.`;
|
|
2909
|
+
}
|
|
2910
|
+
/**
|
|
2911
|
+
* Lists a document's viewers, or changes them. Every removal is matched and every added username
|
|
2912
|
+
* looked up before anything changes. Removals run first, then additions.
|
|
2913
|
+
*/
|
|
2914
|
+
function manageViewers(options) {
|
|
2915
|
+
const { documentId, add, remove } = options;
|
|
2916
|
+
return asOwner(options.server, options.signal, async ({ origin, args }, request) => {
|
|
2917
|
+
const login = {
|
|
2918
|
+
command: "login",
|
|
2919
|
+
args
|
|
2920
|
+
};
|
|
2921
|
+
const next = {
|
|
2922
|
+
command: "viewers",
|
|
2923
|
+
args: [
|
|
2924
|
+
documentId,
|
|
2925
|
+
...args,
|
|
2926
|
+
...remove.flatMap((value) => ["--remove", value]),
|
|
2927
|
+
...add.flatMap((value) => ["--add", value])
|
|
2928
|
+
]
|
|
2929
|
+
};
|
|
2930
|
+
const progress = [];
|
|
2931
|
+
const added = [];
|
|
2932
|
+
const removed = [];
|
|
2933
|
+
const changed = () => added.length || removed.length ? {
|
|
2934
|
+
added,
|
|
2935
|
+
removed
|
|
2936
|
+
} : {};
|
|
2937
|
+
try {
|
|
2938
|
+
const { viewers } = await getDocumentViewers(origin, documentId, request);
|
|
2939
|
+
if (!add.length && !remove.length) return {
|
|
2940
|
+
status: "listed",
|
|
2941
|
+
documentId,
|
|
2942
|
+
viewers,
|
|
2943
|
+
message: viewerList(documentId, viewers)
|
|
2944
|
+
};
|
|
2945
|
+
const removals = [];
|
|
2946
|
+
const notViewers = [];
|
|
2947
|
+
for (const value of remove) {
|
|
2948
|
+
const matches = /^[0-9]+$/u.test(value) ? viewers.filter((viewer) => viewer.githubAccountId === value) : viewers.filter((viewer) => viewer.login.toLowerCase() === value.toLowerCase());
|
|
2949
|
+
if (matches.length > 1) return {
|
|
2950
|
+
status: "ambiguous_viewer",
|
|
2951
|
+
documentId,
|
|
2952
|
+
value,
|
|
2953
|
+
matches,
|
|
2954
|
+
message: [`${value} matches ${matches.length} viewers of ${documentId}. Nothing was changed. Remove one by its GitHub ID with --remove <id>:`, ...matches.map((viewer) => ` ${account(viewer)}`)].join("\n")
|
|
2955
|
+
};
|
|
2956
|
+
if (!matches[0]) notViewers.push(value);
|
|
2957
|
+
else if (!removals.includes(matches[0])) removals.push(matches[0]);
|
|
2958
|
+
}
|
|
2959
|
+
const accounts = [];
|
|
2960
|
+
for (const value of add) {
|
|
2961
|
+
const { user } = await getGitHubUser(origin, value, request);
|
|
2962
|
+
if (user.type !== "user") return {
|
|
2963
|
+
status: "not_personal_account",
|
|
2964
|
+
documentId,
|
|
2965
|
+
user,
|
|
2966
|
+
message: `${account(user)} is ${user.type === "organization" ? "an organization" : "not a personal account"}. Only a personal GitHub account can be a viewer. Nothing was changed.`
|
|
2967
|
+
};
|
|
2968
|
+
progress.push(`Found ${account(user)}.`);
|
|
2969
|
+
if (!accounts.some(({ githubAccountId }) => githubAccountId === user.githubAccountId)) accounts.push(user);
|
|
2970
|
+
}
|
|
2971
|
+
for (const viewer of removals) {
|
|
2972
|
+
await removeDocumentViewer(origin, documentId, viewer.githubAccountId, request);
|
|
2973
|
+
removed.push(viewer);
|
|
2974
|
+
progress.push(`Removed ${account(viewer)}.`);
|
|
2975
|
+
}
|
|
2976
|
+
for (const user of accounts) {
|
|
2977
|
+
const { viewer } = await addDocumentViewer(origin, documentId, user, request);
|
|
2978
|
+
added.push(viewer);
|
|
2979
|
+
progress.push(`Added ${account(viewer)}.`);
|
|
2980
|
+
}
|
|
2981
|
+
const current = await getDocumentViewers(origin, documentId, request);
|
|
2982
|
+
return {
|
|
2983
|
+
status: "viewers_updated",
|
|
2984
|
+
documentId,
|
|
2985
|
+
added,
|
|
2986
|
+
removed,
|
|
2987
|
+
notViewers,
|
|
2988
|
+
viewers: current.viewers,
|
|
2989
|
+
message: [
|
|
2990
|
+
...progress,
|
|
2991
|
+
...notViewers.map((value) => `${value} is not a viewer of ${documentId}.`),
|
|
2992
|
+
viewerList(documentId, current.viewers)
|
|
2993
|
+
].join("\n")
|
|
2994
|
+
};
|
|
2995
|
+
} catch (error) {
|
|
2996
|
+
const prefix = (result) => ({
|
|
2997
|
+
...result,
|
|
2998
|
+
documentId,
|
|
2999
|
+
...changed(),
|
|
3000
|
+
message: [...progress, result.message].join("\n")
|
|
3001
|
+
});
|
|
3002
|
+
if (isRefusal(error)) {
|
|
3003
|
+
const { status } = error;
|
|
3004
|
+
if (status === "github_sign_in_required") return prefix({
|
|
3005
|
+
status,
|
|
3006
|
+
message: `GitHub refused the sign-in Pageship uses to look up GitHub users. Sign in to the Pageship dashboard again with GitHub, then run ${commandLine(next.command, next.args)}.`,
|
|
3007
|
+
next
|
|
3008
|
+
});
|
|
3009
|
+
if (status === "github_rate_limited" || status === "github_unavailable") return prefix({
|
|
3010
|
+
status,
|
|
3011
|
+
message: error.message,
|
|
3012
|
+
next
|
|
3013
|
+
});
|
|
3014
|
+
return prefix(refusal(error, login));
|
|
3015
|
+
}
|
|
3016
|
+
if (!added.length && !removed.length) throw error;
|
|
3017
|
+
return prefix(options.signal.aborted ? {
|
|
3018
|
+
status: "interrupted",
|
|
3019
|
+
message: `Operation interrupted. Run ${commandLine(next.command, next.args)} to finish.`,
|
|
3020
|
+
next
|
|
3021
|
+
} : {
|
|
3022
|
+
status: "request_failed",
|
|
3023
|
+
message: `${error instanceof Error ? error.message : String(error)} Run ${commandLine(next.command, next.args)} to finish.`,
|
|
3024
|
+
next
|
|
3025
|
+
});
|
|
3026
|
+
}
|
|
3027
|
+
});
|
|
3028
|
+
}
|
|
3029
|
+
//#endregion
|
|
2755
3030
|
//#region src/cli.ts
|
|
2756
3031
|
const args = process.argv.slice(2);
|
|
2757
3032
|
const separator = args.indexOf("--");
|
|
@@ -2905,6 +3180,18 @@ const visibility = Command.make("visibility", {
|
|
|
2905
3180
|
visibility,
|
|
2906
3181
|
signal
|
|
2907
3182
|
}))).pipe(Command.withDescription("Make a document private or public."));
|
|
3183
|
+
const viewers = Command.make("viewers", {
|
|
3184
|
+
documentId: documentIdArgument,
|
|
3185
|
+
add: Flag.string("add").pipe(Flag.filter((value) => isGitHubLogin(value), () => "Use a GitHub username."), Flag.withDescription("Look up this GitHub username and add the account it names as a viewer. Repeat to add several."), Flag.atLeast(0)),
|
|
3186
|
+
remove: Flag.string("remove").pipe(Flag.filter((value) => isGitHubLogin(value), () => "Use a viewer's GitHub username or GitHub ID."), Flag.withDescription("Remove the viewer with this GitHub username or GitHub ID. Repeat to remove several."), Flag.atLeast(0)),
|
|
3187
|
+
server: serverFlag
|
|
3188
|
+
}, ({ documentId, add, remove, server }) => authCommand("viewers", (signal) => manageViewers({
|
|
3189
|
+
server: Option.getOrUndefined(server),
|
|
3190
|
+
documentId,
|
|
3191
|
+
add,
|
|
3192
|
+
remove,
|
|
3193
|
+
signal
|
|
3194
|
+
}))).pipe(Command.withDescription("List the GitHub users who can read a private document, or add and remove them."));
|
|
2908
3195
|
const restore = Command.make("restore", {
|
|
2909
3196
|
documentId: documentIdArgument,
|
|
2910
3197
|
server: serverFlag,
|
|
@@ -2977,7 +3264,7 @@ function authCommand(name, operation) {
|
|
|
2977
3264
|
}
|
|
2978
3265
|
});
|
|
2979
3266
|
}
|
|
2980
|
-
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 and restore. Install the Pageship skills for your agents with skills install."), Command.withSubcommands([
|
|
3267
|
+
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."), Command.withSubcommands([
|
|
2981
3268
|
status,
|
|
2982
3269
|
login,
|
|
2983
3270
|
whoami,
|
|
@@ -2986,6 +3273,7 @@ const command = Command.make("pageship").pipe(Command.withDescription("Pageship
|
|
|
2986
3273
|
history,
|
|
2987
3274
|
download,
|
|
2988
3275
|
visibility,
|
|
3276
|
+
viewers,
|
|
2989
3277
|
restore,
|
|
2990
3278
|
skills
|
|
2991
3279
|
]), Command.withGlobalFlags([jsonFlag]));
|
|
@@ -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, 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 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.
|
|
4
4
|
license: MIT
|
|
5
5
|
metadata:
|
|
6
|
-
version: "0.
|
|
6
|
+
version: "0.5.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Pageship
|
|
@@ -97,7 +97,7 @@ After a successful upload the CLI adds the document marker to the end of the loc
|
|
|
97
97
|
On `published`, tell the user:
|
|
98
98
|
|
|
99
99
|
- the document URL, `document.url`;
|
|
100
|
-
- who can read it, from `document.visibility`: a private document opens only for its owner, signed in;
|
|
100
|
+
- who can read it, from `document.visibility`: a private document opens only for its owner and its viewers, signed in;
|
|
101
101
|
- whether this publish created a new document or revised an existing one, from `change`: `created` or `revised`.
|
|
102
102
|
|
|
103
103
|
Keep `idempotencyKey` only while you resolve an uncertain attempt.
|
|
@@ -124,7 +124,11 @@ This works for any document the user owns, even when the file moved or belongs t
|
|
|
124
124
|
|
|
125
125
|
## Share a document
|
|
126
126
|
|
|
127
|
-
A request to share a document, or to send someone its link, is a request to publish it. Publish it as above and report the publish. A new document is private.
|
|
127
|
+
A request to share a document, or to send someone its link, is a request to publish it. Publish it as above and report the publish. A new document is private.
|
|
128
|
+
|
|
129
|
+
When the user names the people to share it with, keep it private and add them as viewers, as in [viewers](references/viewers.md). Sharing with named people never makes a document public.
|
|
130
|
+
|
|
131
|
+
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).
|
|
128
132
|
|
|
129
133
|
## Use another server
|
|
130
134
|
|
|
@@ -137,6 +141,7 @@ Load the reference for the task:
|
|
|
137
141
|
- [List and history](references/list-and-history.md): find a document's `id`, `visibility`, current `revisionId` and `url`, and inspect its revisions.
|
|
138
142
|
- [Download](references/download.md): read a document's HTML, current or from an earlier revision.
|
|
139
143
|
- [Visibility](references/visibility.md): make a document public or private.
|
|
144
|
+
- [Viewers](references/viewers.md): list, add or remove the GitHub users who can read a private document.
|
|
140
145
|
- [Restore](references/restore.md): make an earlier revision current again.
|
|
141
146
|
|
|
142
147
|
Deleting a document, recovering a deleted one, changing a document's display title and revoking a 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.
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Viewers
|
|
2
|
+
|
|
3
|
+
A viewer is a GitHub user who can read a private document after signing in with GitHub. The owner always can. Viewers see only the current revision, never the history.
|
|
4
|
+
|
|
5
|
+
## Share with named people
|
|
6
|
+
|
|
7
|
+
Add viewers only for people the user named in this conversation. When the user names a person without a GitHub username, ask for it; a GitHub username is the only way to name a viewer. Sharing with people keeps the document private: a request to share a document with someone is never a request to make it public. A public document can't have viewers, so if it is public, ask the user whether to make it private first, as in [visibility](visibility.md), and add no one until they agree.
|
|
8
|
+
|
|
9
|
+
Set `PAGESHIP_DOCUMENT` to the document's `id`, then add each named username with its own `--add`:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
pageship --json viewers "$PAGESHIP_DOCUMENT" --add octocat --add hubot
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
The CLI looks each username up on GitHub before it changes anything. `added` holds each account it added, with `login`, `name` and `githubAccountId`, on `viewers_updated` and on a failure partway through. Whatever the status, show the user every account in `added` by `login` and `name`, and ask them to confirm each is the person they meant. A username can belong to someone else. If one is wrong, remove it as below. Then give the user the document's `url` to send: Pageship sends no invitations.
|
|
16
|
+
|
|
17
|
+
## List and remove viewers
|
|
18
|
+
|
|
19
|
+
To see who can read the document, run:
|
|
20
|
+
|
|
21
|
+
```sh
|
|
22
|
+
pageship --json viewers "$PAGESHIP_DOCUMENT"
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
On `listed`, `viewers` holds each viewer's `login`, `name` and `githubAccountId`. A viewer's `login` is the one they had when added or last signed in, so two viewers can show the same `login`.
|
|
26
|
+
|
|
27
|
+
Remove viewers only when the user asks. Pass a `login` or a `githubAccountId`, one `--remove` each. A value of only digits is always a `githubAccountId`, so remove a viewer whose `login` is all digits by its `githubAccountId`:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
pageship --json viewers "$PAGESHIP_DOCUMENT" --remove octocat
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
`notViewers` names values that matched no viewer; nothing was needed for them. On `ambiguous_viewer`, the value matched more than one viewer and nothing changed. Show the user `matches` and ask which one, then remove it by its `githubAccountId`.
|
|
34
|
+
|
|
35
|
+
## Outcomes
|
|
36
|
+
|
|
37
|
+
- `github_user_not_found`, `not_personal_account` or `owner_account`: nothing changed for that username. Report the `message` and ask the user for the right GitHub username. Only a personal account can be a viewer, and the owner can always read their own document.
|
|
38
|
+
- `github_account_mismatch`: the username moved to another account between the lookup and the change. Report the `message` and ask the user to confirm the username before you run the same command again.
|
|
39
|
+
- `document_public`: the document is public. Ask whether to make it private before adding anyone.
|
|
40
|
+
- `github_sign_in_required`: GitHub refused the sign-in Pageship uses to look up users. Ask the user to sign in to the Pageship dashboard again with GitHub, then run the returned `next`. A CLI `login` doesn't fix this.
|
|
41
|
+
- `github_rate_limited` or `github_unavailable`: wait a minute, then run the returned `next`.
|
|
42
|
+
|
|
43
|
+
A failure partway through keeps the changes already made, listed in `added` and `removed`. Its `next` repeats the command, which finishes the rest without adding or removing anyone twice.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Visibility
|
|
2
2
|
|
|
3
|
-
A private document opens only for its owner, signed in. Anyone with the link can read a public one, without signing in.
|
|
3
|
+
A private document opens only for its owner and its [viewers](viewers.md), signed in. Anyone with the link can read a public one, without signing in. Making a document public removes all its viewers.
|
|
4
4
|
|
|
5
5
|
Change visibility only when the user asked for a policy by name, such as "make it public", or agreed when you asked after sharing. Set `PAGESHIP_DOCUMENT` to the document's `id`, then run one of:
|
|
6
6
|
|
|
@@ -9,4 +9,4 @@ pageship --json visibility "$PAGESHIP_DOCUMENT" public
|
|
|
9
9
|
pageship --json visibility "$PAGESHIP_DOCUMENT" private
|
|
10
10
|
```
|
|
11
11
|
|
|
12
|
-
On `visibility_updated`, report the returned `document.visibility` and `document.url
|
|
12
|
+
On `visibility_updated`, report the returned `document.visibility` and `document.url`, and `removedViewers` when it is more than 0. Publishing a new revision keeps the document's visibility.
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pageship-chart
|
|
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.
|
|
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.5.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Chart
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pageship-code-block
|
|
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.
|
|
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.5.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.5.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Decision record
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pageship-diagram
|
|
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.
|
|
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.5.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.5.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.5.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Explainer
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pageship-interaction
|
|
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.
|
|
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.5.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Interaction
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pageship-key-figures
|
|
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.
|
|
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.5.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Key figures
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pageship-media
|
|
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.
|
|
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.5.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Media
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pageship-motion
|
|
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.
|
|
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.5.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.5.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.5.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.5.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.5.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.5.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Spec
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: pageship-table
|
|
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.
|
|
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.5.0"
|
|
7
7
|
---
|
|
8
8
|
|
|
9
9
|
# Table
|