Community编程与开发github.com

leynier/portifact

使用 Portifact 发布和分享静态制品(HTML 网站、Markdown 和纯文本),控制谁可以查看它们,并收集审阅者的注释。当用户想要以链接的形式分享计划、报告、原型或文档,或者提到 Portifact、portifact CLI 或 Portifact MCP 服务器时使用。

portifact 是什么?

Portifact 是一个专门用于发布和分享静态制品的工具,支持 HTML 网站、Markdown 文档和纯文本文件。它通过 `portifact` CLI 或远程 MCP 服务器集成到 AI 代理(如 Claude Code、Cursor、Codex)的工作流程中,为每个制品生成唯一的 URL,并提供了精细的访问控制、过期和恢复机制。核心功能包括:使用 OAuth 设备流进行身份验证、预览和发布制品(支持文件夹、ZIP、HTML、Markdown 和文本文件)、管理制品(列表、续期、归档、恢复和删除)、通过受限/认证/公开模式控制访问、版本管理(列表、回滚和下载)以及收集来自认证审阅者的注释线程。Portifact 通过从 GitHub 发布页面下载的单一可执行文件运行,无需 Node 或 Bun 依赖,其 CLI 使用 `--json` 输出以实现可解析的结果,非常适合自动化工作流。该工具还支持附加私有源码、发布 Markdown 资产、处理 Git 集成(用于源码版本控制)以及报告使用情况和访问日志,使其成为在受控环境中向利益相关者分享开发计划、原型或文档的可靠解决方案。

兼容平台✓Claude Code✓Codex CLI✓Cursor
npx skills add https://github.com/leynier/portifact/tree/HEAD/skills/portifact

Installed? Explore more 编程与开发 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

portifact 是做什么的?

Portifact 可以发布静态制品,并为每个制品分配独立的 URL,支持访问控制、过期和恢复,并且可选地收集来自已认证审阅者的注释。代理通过 portifact CLI 或远程 MCP 服务器使用它。

检查已安装版本支持的功能

Portifact 正处于早期开发阶段,每个版本都会增加新的命令。在使用任何命令之前:

  1. 运行 portifact --version 确认 CLI 已安装。
  2. 运行 portifact --help 查看此版本支持的命令。
  3. 仅使用 --help 列出的命令和标志。切勿猜测命令。如果用户要求的功能当前安装版本无法实现,请明确告知并建议更新。

如果版本的 --help 列出了 login,则该版本支持登录、注销和显示已登录账户。如果 --help 也列出了 publish,则该版本可以发布文件和文件夹,并管理制品及其访问权限;如果 --help 列出了 versions、rollback 和 pull,则该版本可以列出版本、回滚和下载;如果 --help 列出了 annotations,则该版本可以管理评论线程,如下所述。如果 portifact publish --help 列出了 --source、--ref 和 --assets,则该版本支持发布 ZIP 文件、附加私有源码和发布 Markdown 资产;如果 portifact pull --help 列出了 --git,则该版本可以为私有源码构建 Git 历史;如果 --help 列出了 usage,则该版本可以显示账户配额;如果 --help 列出了 logs,则该版本可以显示谁打开了制品;如果 --help 列出了 licenses,则该版本可以打印二进制文件中使用的开源软件许可证(portifact licenses;也可见 https://portifact.com/third-party-notices)。位于 https://app.portifact.com/mcp 的 MCP 服务器可以列出、发布和管理小型文档;列出、下载和回滚版本;读取、写入、审核和导出注释;以及报告使用情况和访问日志;详情见下文。

安装或更新 CLI

CLI 是一个单一的可执行文件,不需要 Node 或 Bun。在用户机器上安装软件前请先征得同意。

curl -fsSL https://portifact.com/install | bash
irm https://portifact.com/install.ps1 | iex
  • 在 Alpine Linux 上,请先安装 C++ 运行时:apk add libstdc++ libgcc。
  • 重新运行相同的命令进行更新。
  • 设置 PORTIFACT_VERSION=0.2.0 以安装指定版本。
  • 在非交互式或沙盒环境中,设置 PORTIFACT_NO_MODIFY_PATH=1 并直接调用 ~/.portifact/bin/portifact,而不是修改 shell 配置文件。
  • 安装程序会对照发布版本的校验和验证下载,如果校验和不匹配则会停止。不要绕过失败的验证。

登录

首先使用 portifact whoami --json 检查。退出码 0 表示已登录,并打印 {"server","userId","clientId","scopes"};退出码 3 表示此设备未登录或会话已过期。

要登录,请运行 portifact login(添加 --json 以获得可解析的结果)。它使用 OAuth 设备流:

  1. CLI 会在 stderr 上打印一个页面地址(https://app.portifact.com/device)和一个 8 位字符的代码。如果用户在终端前,CLI 会自动打开浏览器。传递 --no-browser 可以跳过打开浏览器。
  2. 向用户显示确切的页面地址和代码,并请他们在该页面登录,检查页面是否显示相同的代码,然后批准。永远不要代替用户批准,也不要要求用户从该页面粘贴任何内容回传给您。登录页面会要求用户确认他们年满 18 岁并接受服务条款(https://portifact.com/terms);这个选择是用户自己的,不要代替他们接受。如果页面提示无法向他们的电子邮件地址发送验证码(由于之前的邮件被退回或被举报为垃圾邮件),或者本月电子邮件验证码已暂停,请告知用户改用 Google 或 GitHub 登录。
  3. 命令会一直等待,直到用户批准或拒绝,或者代码过期(10 分钟),因此请在用户能看到其 stderr 的地方运行它,并让它自然结束。

凭据会保存到操作系统的凭据存储中。当没有凭据存储时(例如没有 Secret Service 服务的 Linux 服务器),它们会保存到用户配置目录下的 credentials.json 文件中(Linux 上为 ~/.config/portifact,macOS 上为 ~/Library/Application Support/portifact,Windows 上为 %APPDATA%\portifact),并设置仅为用户可访问的权限,同时 CLI 会打印一条警告。切勿读取、打印、复制或上传该文件或存储的令牌;CLI 会自动刷新它们。

portifact logout 会在服务器上撤销此设备的令牌,然后将其删除。它会撤销令牌,因此请先与用户确认。如果无法访问服务器,它会保留凭据并退出,返回退出码 1;请稍后重新运行。

PORTIFACT_APP_ORIGIN 用于将 CLI 指向另一台服务器,主要用于测试和预发布环境。除非用户要求,否则不要设置它。

发布

仅适用于 --help 列出 publish 的版本。

  1. 首先预览:运行 portifact publish <path> --dry-run --json 会在不登录或上传的情况下构建清单。它返回 {"dryRun","type","name","entrypoint","totalBytes","files":[{"path","size","sha256","contentType"}],"excluded":[{"path","reason"}]},如果使用了 --source,还会返回 "sources":{"chosenBy","totalBytes","files","excluded","origin","lfsPointers"}。向用户显示文件、源码以及被排除的内容,如果发现任何看起来是私有的内容,请停止操作。
  2. 发布:运行 portifact publish <path> --json。结果返回 {"artifactId","versionId","versionNumber","url","expiresAt","uploadId","files","totalBytes","sourceFiles","sourceBytes","sourceOrigin","uploadedFiles","uploadedBytes"}。进度信息和清单会输出到 stderr。
  • 类型是根据路径推断的:文件夹、.zip 文件或 .html 文件被视为 site,.md 被视为 markdown,.txt 被视为 text。对于其他文件,请传递 --type site|markdown|text。文件夹和 ZIP 文件只能是站点(site)。
  • 单个 HTML 文件将作为站点的 index.html 发布。文件夹需要包含一个 index.html,或者使用 --entry <path> 指定一个首先打开的页面。
  • --name 用于设置制品列表中显示的名称;默认使用文件或文件夹的名称。
  • --artifact <id> 用于发布现有制品的新版本,保留其名称、类型和访问权限,除非使用 --name 更改了名称。如果在此过程中其他人发布了版本,则会失败并返回 version_conflict(退出码 6);请检查制品的版本列表,然后重新发布。
  • 文件夹总是排除 .git、node_modules、缓存、操作系统文件以及可能包含秘密的文件(例如 .env 和 .env.*,但不包括示例文件、.dev.vars、.npmrc、.netrc、SSH 密钥、*.pem、*.key、*.p12、Terraform 状态文件等)。直接指定此类文件发布会被拒绝。这个过滤器是一个安全网,而不是代码审查工具:仍然需要检查清单。
  • 符号链接和特殊文件会被拒绝,不会被跟踪。
  • 账户中已存储的文件不会再次上传。中断的上传会重试,如果发布在上传开始后失败,CLI 会取消它,以确保不会半发布内容。
  • 如果版本的进度显示 Uploaded part <n> of <m> of <path>,则说明该版本会将超过 64 MiB 的文件分成 16 MiB 的片段从磁盘流式上传,因此大文件无需完全加载到内存中,并且失败的片段可以单独重新发送。一个版本最多包含 250 MB 的发布文件,无论片段大小如何。
  • ZIP 文件会在用户机器上解压,然后才上传任何内容。如果其中的所有文件都位于一个文件夹内,则该文件夹将成为根目录。链接、特殊文件、加密条目、试图离开压缩包的文件、名称冲突、重叠条目、解压后大小超过声明大小超过 200 倍的文件、超过 10,000 个条目以及任何超出大小限制的内容都会被拒绝(invalid_input,退出码 2,或 quota_exceeded,退出码 7)。默认排除规则和秘密过滤器同样适用于 ZIP 文件中的条目。
  • --source <path> 用于将私有源码附加到该版本:只有所有者才能查看和下载它们(使用 pull --source),它们计入存储空间,但不计入已发布文件的大小,并且已发布文件和源文件总数最多为 1,000。路径可以是文件夹、单个文件或 ZIP 文件。如果路径是 git 仓库内的文件夹,git 将选择文件:即它版本控制的文件加上它不忽略的新文件,但不包括子模块或嵌套仓库。使用 --ref <commit> 可以只附加该提交对应的树结构(可以是分支、标签或提交 ID;它永远不会包含未提交的更改)。然后,CLI 会将提交、分支、不含凭据的远程地址以及是否有未提交的更改记录为该版本的 sourceOrigin。如果在仓库外部,或者未安装 git,则使用默认排除规则遍历文件夹。即使 git 包含,可能包含秘密的文件也绝不会被附加。如果 stderr 上出现警告,列出了 Git LFS 指针(这些指针作为指针本身附加,而不是内容),建议先运行 git lfs pull。
  • --assets <dir> 用于发布一个包含图片和其他文件的文件夹,与一个 Markdown 文档一起发布,这些文件相对于该文档的路径保持不变,以便其相对链接能够正常工作。该文件夹必须位于文档所在的文件夹内部,并且默认排除规则适用。
  • Portifact 会自行渲染 markdown 或 text 制品:其 URL 会打开一个由该文档渲染的页面,其中 Markdown 中的原始 HTML 会显示为文本,并且不会执行任何脚本。原始文件可以通过制品 URL 下自己的路径下载(例如 <url>plan.md,或对于 publish_document 的 <url>index.md),具有与页面相同的访问权限。一个文档最多 5 MB 的 UTF-8 文本,一个 text 制品是单个文件。

管理制品

仅适用于 --help 列出这些命令的版本。每个命令都支持 --json。

  • portifact list [--limit N] [--cursor C] [--search TEXT] [--state active|archived|suspended|purging] [--type site|markdown|text] [--access public|authenticated|restricted] [--annotations off|open|locked] 返回 {"items":[...],"nextCursor"};将 nextCursor 作为 --cursor 的值,并保持相同的过滤器,以获取下一页。每个项目是 portifact info 返回的内容加上 "activity":{"versions","currentBytes","openThreads","lastAnnotationAt"}:即保留的版本(包括当前版本)、当前版本的字节数(发布文件和源码,如果没有版本则为 null)、当前版本上打开的线程以及任何版本上线程最后更改的时间(如果没有线程则为 null)。流量是每个账户计费的,而不是每个制品,因此它只在 portifact usage 中显示。--search 会匹配名称的一部分(不区分大小写)或 ID 的一部分,并且所有给定的过滤器必须同时成立,因此使用它们来查找制品,而不是翻遍所有页面。portifact info <id> 返回一个项目:{"id","name","type","state","accessMode","annotations","currentVersionId","url","expiresAt","archivedAt","purgeAt","createdAt","updatedAt"},此外,当制品被暂停时,还会包含 "suspension":{"reason"}。
  • portifact renew <id>、archive <id> 和 restore <id> 返回 {"artifactId","state","expiresAt","purgeAt"}。归档前请先询问用户。
  • portifact delete <id> 会永久删除。它会要求终端前的用户输入制品 ID;如果没有终端,则需要 --yes,否则会失败并返回退出码 2。只有在用户确认了该确切制品后,才能传递 --yes。

控制访问

仅适用于 --help 列出 access 的版本。每个命令都支持 --json,并打印 {"artifactId","mode","readers","indexable","embeddable","policyGeneration"}。

  • portifact access <id> 显示当前策略。在发布后使用它来报告访问模式。
  • portifact access set <id> restricted|authenticated|public:restricted 是所有者加上列出的读者;authenticated 是任何登录到 Portifact 的人;public 是任何拥有链接的人。在创建后的前 7 天内,账户不能将制品设为公开(account_too_new_for_public,退出码 7)。
  • portifact access add <id> <email>... 和 access remove <id> <email>... 用于更改读者列表(一次最多 100 个地址)。读者仅在模式为 restricted 时起作用。

版本、回滚和下载

仅适用于 --help 列出这些命令的版本。每个命令都支持 --json。

一个制品会保留其当前版本以及在过去七天内替换掉的版本。回滚和下载仅适用于这些保留的版本。

  • portifact versions <id> 列出版本,最新的在前。--json 打印 {"artifactId","items":[{"id","number","current","entrypoint","publishedBytes","sourceBytes","publishedFiles","sourceFiles","rendererVersion","committedAt","expiresAt","sourceOrigin"}]};expiresAt 是前一个版本停止被保留的时间,对于当前版本则为 null;sourceOrigin 在源码来自 git 时为 {"commit","branch","remote","dirty"},否则为 null。此来源信息是发布者声明的;Portifact 无法验证其真实性。
  • portifact rollback <id> <version-id> 使一个保留的版本再次成为当前版本。它会作为一个具有相同文件的新版本发布,重新开始 30 天的保留期,并且不会改变访问控制:自该版本以来被移除的读者仍然无法访问。在回滚前请询问用户。它返回 {"artifactId","versionId","versionNumber","url","expiresAt","fromVersionId","fromVersionNumber"}。如果在此过程中有人发布了版本,则会失败并返回 version_conflict(退出码 6);请再次检查 versions 并询问用户。在 portifact rollback --help 显示“version ID or number”的版本中,<version-id> 也可以是版本号(3 或 v3),pull --version 也接受版本号;如果提供的版本号未被保留,则会失败并返回 not_found(退出码 5)。
  • portifact pull <id> --out <dir> 将当前版本已发布的文件下载到 <dir>/published 目录下。添加 --source 参数可以下载私有源码(到 <dir>/source 目录,仅所有者可下载),添加 --published --source 参数可以两者都下载,添加 --version <version-id> 参数可以下载先前的版本。<dir> 目录不能已存在;pull 绝不会在 <dir> 目录之外写入文件,会拒绝写入 .git 文件夹内的路径,会检查每个文件的 SHA-256 哈希值,如果任何文件校验失败,则会删除 <dir> 目录(download_failed,退出码 1)。它返回 {"artifactId","versionId","versionNumber","out","files":[{"kind","path","size","sha256"}],"totalBytes"}。与某人共享的制品……

相关技能