From 0e89ed3248ac57291f980cbfe3cfa382bbf5085b Mon Sep 17 00:00:00 2001 From: Odboy Date: Tue, 3 Nov 2026 22:05:00 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=96=B0=E5=A2=9E=20pkg.install/remove?= =?UTF-8?q?/search/info=20=E5=8C=85=E7=AE=A1=E7=90=86=E5=91=BD=E4=BB=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.pkg.md | 88 ++++++++- internal/executor/builtin.go | 116 ++++++------ internal/executor/pkgmanage.go | 288 +++++++++++++++++++++++++++++ internal/registry/builtin.go | 130 +++++++++++++ internal/registry/registry_test.go | 6 +- 5 files changed, 572 insertions(+), 56 deletions(-) create mode 100644 internal/executor/pkgmanage.go diff --git a/README.pkg.md b/README.pkg.md index fe6ec8d..72a843d 100644 --- a/README.pkg.md +++ b/README.pkg.md @@ -2,13 +2,28 @@ > 返回 [README.md](README.md) -刷新系统包管理器的软件源索引,或列出已安装的软件包。 +管理软件包:列出、搜索、安装、卸载、刷新索引。 ```bash kopsc pkg list # 列出已安装的软件包 -kopsc pkg refreshindex # 刷新包管理器索引(dnf/apt/apk/brew/winget,按平台自动选) +kopsc pkg search nginx # 搜索软件包 +kopsc pkg install nginx # 安装软件包 +kopsc pkg remove nginx # 卸载软件包 +kopsc pkg info nginx # 查看软件包详情 +kopsc pkg refreshindex # 刷新包管理器索引 ``` +## 命令一览 + +| 命令 | 作用 | +| --- | --- | +| `kopsc pkg list` | 列出已安装的软件包 | +| `kopsc pkg search <关键字>` | 搜索软件包 | +| `kopsc pkg install <包名>` | 安装软件包(需 `--yes`) | +| `kopsc pkg remove <包名>` | 卸载软件包(需 `--yes`) | +| `kopsc pkg info <包名>` | 查看软件包详情 | +| `kopsc pkg refreshindex` | 刷新包管理器索引 | + ## 列出已安装的软件包(pkg.list) ```bash @@ -25,6 +40,75 @@ kopsc pkg list | macOS | `brew list` | | Windows | `winget list` | +## 搜索软件包(pkg.search) + +```bash +kopsc pkg search nginx +kopsc pkg search redis +``` + +在软件源中搜索匹配关键字的软件包。 + +| 平台 | 实际执行 | +| --- | --- | +| Linux(Debian/Ubuntu) | `apt-cache search` | +| Linux(CentOS/RHEL/Fedora) | `dnf search` | +| Linux(Alpine) | `apk search` | +| macOS | `brew search` | +| Windows | `winget search` | + +## 安装软件包(pkg.install) + +```bash +kopsc pkg install nginx # 预览将执行的操作 +kopsc pkg install nginx --yes # 确认安装 +kopsc pkg install nginx redis -y # 安装多个包 +``` + +安装指定的软件包。这是破坏性命令,需要 `--yes` 确认。 + +| 平台 | 实际执行 | +| --- | --- | +| Linux(Debian/Ubuntu) | `apt-get install` | +| Linux(CentOS/RHEL/Fedora) | `dnf install` | +| Linux(Alpine) | `apk add` | +| macOS | `brew install` | +| Windows | `winget install` | + +## 卸载软件包(pkg.remove) + +```bash +kopsc pkg remove nginx # 预览将执行的操作 +kopsc pkg remove nginx --yes # 确认卸载 +``` + +卸载指定的软件包。这是破坏性命令,需要 `--yes` 确认。 + +| 平台 | 实际执行 | +| --- | --- | +| Linux(Debian/Ubuntu) | `apt-get remove` | +| Linux(CentOS/RHEL/Fedora) | `dnf remove` | +| Linux(Alpine) | `apk del` | +| macOS | `brew uninstall` | +| Windows | `winget uninstall` | + +## 查看软件包详情(pkg.info) + +```bash +kopsc pkg info nginx +kopsc pkg info python3 +``` + +显示指定软件包的详细信息(版本、描述、依赖等)。 + +| 平台 | 实际执行 | +| --- | --- | +| Linux(Debian/Ubuntu) | `apt show`(回退 `dpkg -s`) | +| Linux(CentOS/RHEL/Fedora) | `rpm -qi` | +| Linux(Alpine) | `apk info -a` | +| macOS | `brew info` | +| Windows | `winget show` | + ## 刷新软件源索引(pkg.refreshindex) `kopsc pkg refreshindex` 刷新本机包管理器的软件源索引,**只更新索引,不升级也不安装任何软件包**。 diff --git a/internal/executor/builtin.go b/internal/executor/builtin.go index 5427f7d..11ed816 100644 --- a/internal/executor/builtin.go +++ b/internal/executor/builtin.go @@ -32,62 +32,72 @@ type BuiltinRequest struct { type Builtin func(ctx context.Context, req BuiltinRequest) error var builtins = map[string]Builtin{ - "archive.extract": runArchiveExtract, - "disk.usage": runDiskUsage, - "diagnose": runDiagnose, - "docker.df": runDockerDF, - "docker.exec": runDockerExec, - "docker.load": runDockerLoad, - "docker.logs": runDockerLogs, - "docker.restart": runDockerRestart, - "docker.rm": runDockerRM, + "archive.create": runArchiveCreate, + "archive.extract": runArchiveExtract, + "archive.list": runArchiveList, + "disk.check": runDiskCheck, + "disk.inode": runDiskInode, + "disk.usage": runDiskUsage, + "diagnose": runDiagnose, + "docker.df": runDockerDF, + "docker.exec": runDockerExec, + "docker.load": runDockerLoad, + "docker.logs": runDockerLogs, + "docker.restart": runDockerRestart, + "docker.rm": runDockerRM, "docker.rm.preview": runDockerPreviewRM, - "docker.rmi": runDockerRMI, + "docker.rmi": runDockerRMI, "docker.rmi.preview": runDockerPreviewRMI, - "docker.save": runDockerSave, - "docker.stats": runDockerStats, - "docker.stop": runDockerStop, - "file.empty": runFileEmpty, - "file.findbig": runFileFindBig, - "file.findname": runFileFindName, - "file.findrecent": runFileFindRecent, - "fw.allow": runFwAllow, - "fw.deny": runFwDeny, - "fw.status": runFwStatus, - "git.retime": runGitRetime, + "docker.save": runDockerSave, + "docker.stats": runDockerStats, + "docker.stop": runDockerStop, + "file.empty": runFileEmpty, + "file.findbig": runFileFindBig, + "file.findname": runFileFindName, + "file.findrecent": runFileFindRecent, + "fw.allow": runFwAllow, + "fw.deny": runFwDeny, + "fw.status": runFwStatus, + "git.retime": runGitRetime, "git.retime.preview": runGitRetimePreview, - "java.run": runJavaRun, - "java.run.preview": runJavaPreview, - "log.last": runLogLast, - "log.list": runLogList, - "log.search": runLogSearch, - "net.conn": runNetConn, - "net.curl": runNetCurl, - "net.dns": runNetDNS, - "net.iface": runNetIface, - "net.ping": runNetPing, - "net.pids": runNetPIDs, - "net.ports": runNetPorts, - "net.speed": runNetSpeed, - "net.trace": runNetTrace, - "pkg.list": runPkgList, - "proc.killname": runProcKillName, - "proc.list": runProcList, - "proc.nohup": runNohup, - "proc.topcpu": runProcTopCPU, - "proc.topmem": runProcTopMem, - "proc.tree": runProcTree, - "proc.wait": runProcWait, - "svc.disable": runSvcDisable, - "svc.enable": runSvcEnable, - "svc.list": runSvcList, - "svc.logs": runSvcLogs, - "svc.status": runSvcStatus, - "sysinfo": runSysInfo, - "user.grant": runUserGrant, - "user.info": runUserInfo, - "user.list": runUserList, - "user.revoke": runUserRevoke, + "git.time": runGitTime, + "java.run": runJavaRun, + "java.run.preview": runJavaPreview, + "log.last": runLogLast, + "log.list": runLogList, + "log.search": runLogSearch, + "net.conn": runNetConn, + "net.curl": runNetCurl, + "net.dns": runNetDNS, + "net.http": runNetHTTP, + "net.iface": runNetIface, + "net.ping": runNetPing, + "net.pids": runNetPIDs, + "net.ports": runNetPorts, + "net.speed": runNetSpeed, + "net.trace": runNetTrace, + "pkg.info": runPkgInfo, + "pkg.install": runPkgInstall, + "pkg.list": runPkgList, + "pkg.remove": runPkgRemove, + "pkg.search": runPkgSearch, + "proc.killname": runProcKillName, + "proc.list": runProcList, + "proc.nohup": runNohup, + "proc.topcpu": runProcTopCPU, + "proc.topmem": runProcTopMem, + "proc.tree": runProcTree, + "proc.wait": runProcWait, + "svc.disable": runSvcDisable, + "svc.enable": runSvcEnable, + "svc.list": runSvcList, + "svc.logs": runSvcLogs, + "svc.status": runSvcStatus, + "sysinfo": runSysInfo, + "user.grant": runUserGrant, + "user.info": runUserInfo, + "user.list": runUserList, + "user.revoke": runUserRevoke, } // runDiagnose bridges the registry builtin to the diagnose package. diff --git a/internal/executor/pkgmanage.go b/internal/executor/pkgmanage.go new file mode 100644 index 0000000..77b26b0 --- /dev/null +++ b/internal/executor/pkgmanage.go @@ -0,0 +1,288 @@ +package executor + +import ( + "context" + "fmt" + "os/exec" + "runtime" + "strings" + + "gitea.odboy.cn/odboy/kenaito-kopsc/internal/platform" +) + +// runPkgInstall implements `kopsc pkg install `: install a package. +func runPkgInstall(ctx context.Context, req BuiltinRequest) error { + opts, err := parsePkgManageArgs(req.Args, "install") + if err != nil { + return err + } + if len(opts.packages) == 0 { + return fmt.Errorf("缺少包名;用法: kopsc pkg install <包名> [包名...]") + } + + switch runtime.GOOS { + case "linux": + return pkgInstallLinux(ctx, req, opts.packages) + case "darwin": + args := append([]string{"install"}, opts.packages...) + cmd := exec.CommandContext(ctx, "brew", args...) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + case "windows": + args := append([]string{"install"}, opts.packages...) + cmd := exec.CommandContext(ctx, "winget", args...) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + default: + return fmt.Errorf("不支持的操作系统: %s", runtime.GOOS) + } +} + +func pkgInstallLinux(ctx context.Context, req BuiltinRequest, packages []string) error { + info := platform.System().Detect() + + // Debian/Ubuntu: apt-get install + if distroLikeContains(info, "debian", "ubuntu") { + args := append([]string{"install"}, packages...) + cmd := exec.CommandContext(ctx, "apt-get", args...) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + } + + // CentOS/RHEL/Fedora: dnf install + if distroLikeContains(info, "rhel", "fedora") || info.Distro == "centos" { + args := append([]string{"install"}, packages...) + cmd := exec.CommandContext(ctx, "dnf", args...) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + } + + // Alpine: apk add + if info.Distro == "alpine" { + args := append([]string{"add"}, packages...) + cmd := exec.CommandContext(ctx, "apk", args...) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + } + + return fmt.Errorf("不支持的 Linux 发行版: %s", info.Distro) +} + +// runPkgRemove implements `kopsc pkg remove `: remove a package. +func runPkgRemove(ctx context.Context, req BuiltinRequest) error { + opts, err := parsePkgManageArgs(req.Args, "remove") + if err != nil { + return err + } + if len(opts.packages) == 0 { + return fmt.Errorf("缺少包名;用法: kopsc pkg remove <包名> [包名...]") + } + + switch runtime.GOOS { + case "linux": + return pkgRemoveLinux(ctx, req, opts.packages) + case "darwin": + args := append([]string{"uninstall"}, opts.packages...) + cmd := exec.CommandContext(ctx, "brew", args...) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + case "windows": + args := append([]string{"uninstall"}, opts.packages...) + cmd := exec.CommandContext(ctx, "winget", args...) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + default: + return fmt.Errorf("不支持的操作系统: %s", runtime.GOOS) + } +} + +func pkgRemoveLinux(ctx context.Context, req BuiltinRequest, packages []string) error { + info := platform.System().Detect() + + // Debian/Ubuntu: apt-get remove + if distroLikeContains(info, "debian", "ubuntu") { + args := append([]string{"remove"}, packages...) + cmd := exec.CommandContext(ctx, "apt-get", args...) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + } + + // CentOS/RHEL/Fedora: dnf remove + if distroLikeContains(info, "rhel", "fedora") || info.Distro == "centos" { + args := append([]string{"remove"}, packages...) + cmd := exec.CommandContext(ctx, "dnf", args...) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + } + + // Alpine: apk del + if info.Distro == "alpine" { + args := append([]string{"del"}, packages...) + cmd := exec.CommandContext(ctx, "apk", args...) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + } + + return fmt.Errorf("不支持的 Linux 发行版: %s", info.Distro) +} + +// runPkgSearch implements `kopsc pkg search `: search for packages. +func runPkgSearch(ctx context.Context, req BuiltinRequest) error { + opts, err := parsePkgManageArgs(req.Args, "search") + if err != nil { + return err + } + if len(opts.packages) == 0 { + return fmt.Errorf("缺少搜索关键字;用法: kopsc pkg search <关键字>") + } + keyword := opts.packages[0] + + switch runtime.GOOS { + case "linux": + return pkgSearchLinux(ctx, req, keyword) + case "darwin": + cmd := exec.CommandContext(ctx, "brew", "search", keyword) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + case "windows": + cmd := exec.CommandContext(ctx, "winget", "search", keyword) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + default: + return fmt.Errorf("不支持的操作系统: %s", runtime.GOOS) + } +} + +func pkgSearchLinux(ctx context.Context, req BuiltinRequest, keyword string) error { + info := platform.System().Detect() + + // Debian/Ubuntu: apt-cache search + if distroLikeContains(info, "debian", "ubuntu") { + cmd := exec.CommandContext(ctx, "apt-cache", "search", keyword) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + } + + // CentOS/RHEL/Fedora: dnf search + if distroLikeContains(info, "rhel", "fedora") || info.Distro == "centos" { + cmd := exec.CommandContext(ctx, "dnf", "search", keyword) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + } + + // Alpine: apk search + if info.Distro == "alpine" { + cmd := exec.CommandContext(ctx, "apk", "search", keyword) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + } + + return fmt.Errorf("不支持的 Linux 发行版: %s", info.Distro) +} + +// runPkgInfo implements `kopsc pkg info `: show package details. +func runPkgInfo(ctx context.Context, req BuiltinRequest) error { + opts, err := parsePkgManageArgs(req.Args, "info") + if err != nil { + return err + } + if len(opts.packages) == 0 { + return fmt.Errorf("缺少包名;用法: kopsc pkg info <包名>") + } + pkg := opts.packages[0] + + switch runtime.GOOS { + case "linux": + return pkgInfoLinux(ctx, req, pkg) + case "darwin": + cmd := exec.CommandContext(ctx, "brew", "info", pkg) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + case "windows": + cmd := exec.CommandContext(ctx, "winget", "show", pkg) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + default: + return fmt.Errorf("不支持的操作系统: %s", runtime.GOOS) + } +} + +func pkgInfoLinux(ctx context.Context, req BuiltinRequest, pkg string) error { + info := platform.System().Detect() + + // Debian/Ubuntu: apt show (fallback to dpkg -s) + if distroLikeContains(info, "debian", "ubuntu") { + cmd := exec.CommandContext(ctx, "apt", "show", pkg) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + if err := cmd.Run(); err != nil { + // Fallback to dpkg -s + cmd = exec.CommandContext(ctx, "dpkg", "-s", pkg) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + } + return nil + } + + // CentOS/RHEL/Fedora: rpm -qi + if distroLikeContains(info, "rhel", "fedora") || info.Distro == "centos" { + cmd := exec.CommandContext(ctx, "rpm", "-qi", pkg) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + } + + // Alpine: apk info + if info.Distro == "alpine" { + cmd := exec.CommandContext(ctx, "apk", "info", "-a", pkg) + cmd.Stdout = req.Stdout + cmd.Stderr = req.Stderr + return cmd.Run() + } + + return fmt.Errorf("不支持的 Linux 发行版: %s", info.Distro) +} + +type pkgManageOptions struct { + packages []string +} + +func parsePkgManageArgs(args []string, action string) (pkgManageOptions, error) { + var opts pkgManageOptions + var positional []string + + for i := 0; i < len(args); i++ { + arg := args[i] + switch { + case arg == "--": + positional = append(positional, args[i+1:]...) + i = len(args) + case strings.HasPrefix(arg, "-") && arg != "-": + // Ignore unknown flags, pass through + positional = append(positional, arg) + default: + positional = append(positional, arg) + } + } + + opts.packages = positional + return opts, nil +} diff --git a/internal/registry/builtin.go b/internal/registry/builtin.go index e4d1b66..a29b71f 100644 --- a/internal/registry/builtin.go +++ b/internal/registry/builtin.go @@ -513,6 +513,35 @@ func Builtin() *Registry { }, }, }, + { + ID: "git.time", + Group: "git", + Summary: "修改最后一次提交的时间并强推", + Action: "把本地最后一次提交的作者时间和提交时间改为用户指定的时间,然后强制推送到远程。" + + "时间格式必须是 yyyy-MM-dd HH:mm:ss(如 2026-11-05 22:30:00)。" + + "同时修改 Author Date 和 Committer Date,确保远程页面显示正确。" + + "默认只打印预览并以退出码 2 结束,必须显式加 --yes 才会改写并推送", + Usage: "<时间> [选项]", + MinArgs: 1, + RequiresYes: true, + Variants: []Variant{ + { + Match: Match{OS: "linux"}, + Builtin: "git.time", + Note: "Linux 内置实现(调用本机 git)", + }, + { + Match: Match{OS: "darwin"}, + Builtin: "git.time", + Note: "macOS 内置实现(调用本机 git)", + }, + { + Match: Match{OS: "windows"}, + Builtin: "git.time", + Note: "Windows 内置实现(调用本机 git)", + }, + }, + }, { ID: "pkg.list", Group: "pkg", @@ -937,6 +966,107 @@ func Builtin() *Registry { Usage: "[用户名]", Variants: threePlatformBuiltins("user.info"), }, + + // ----- pkg additions ----- + { + ID: "pkg.install", + Group: "pkg", + Summary: "安装软件包", + Action: "安装指定的软件包。" + + "Linux: apt-get install(Debian/Ubuntu)/ dnf install(CentOS/RHEL)/ apk add(Alpine);" + + "macOS: brew install;Windows: winget install", + Usage: "<包名> [包名...]", + MinArgs: 1, + RequiresYes: true, + Variants: threePlatformBuiltins("pkg.install"), + }, + { + ID: "pkg.remove", + Group: "pkg", + Summary: "卸载软件包", + Action: "卸载指定的软件包。" + + "Linux: apt-get remove(Debian/Ubuntu)/ dnf remove(CentOS/RHEL)/ apk del(Alpine);" + + "macOS: brew uninstall;Windows: winget uninstall", + Usage: "<包名> [包名...]", + MinArgs: 1, + RequiresYes: true, + Variants: threePlatformBuiltins("pkg.remove"), + }, + { + ID: "pkg.search", + Group: "pkg", + Summary: "搜索软件包", + Action: "在软件源中搜索匹配关键字的软件包。" + + "Linux: apt-cache search(Debian/Ubuntu)/ dnf search(CentOS/RHEL)/ apk search(Alpine);" + + "macOS: brew search;Windows: winget search", + Usage: "<关键字>", + MinArgs: 1, + Variants: threePlatformBuiltins("pkg.search"), + }, + { + ID: "pkg.info", + Group: "pkg", + Summary: "查看软件包详情", + Action: "显示指定软件包的详细信息(版本、描述、依赖等)。" + + "Linux: apt show / dpkg -s(Debian/Ubuntu)/ rpm -qi(CentOS/RHEL)/ apk info(Alpine);" + + "macOS: brew info;Windows: winget show", + Usage: "<包名>", + MinArgs: 1, + Variants: threePlatformBuiltins("pkg.info"), + }, + + // ----- archive additions ----- + { + ID: "archive.create", + Group: "archive", + Summary: "创建压缩文件", + Action: "将文件或目录压缩为归档文件。支持 tar.gz / tgz / tar / zip 格式,默认 tar.gz。" + + "--format 可指定格式,-o 可指定输出文件名", + Usage: "<路径> [--format 格式] [-o 输出文件]", + MinArgs: 1, + Variants: threePlatformBuiltins("archive.create"), + }, + { + ID: "archive.list", + Group: "archive", + Summary: "列出压缩文件内容(不解压)", + Action: "查看压缩文件的内容列表,显示权限、大小、修改时间和文件名。" + + "支持 tar.gz / tgz / tar / zip 格式", + Usage: "<文件>", + MinArgs: 1, + Variants: threePlatformBuiltins("archive.list"), + }, + + // ----- net additions (http) ----- + { + ID: "net.http", + Group: "net", + Summary: "启动简单的 HTTP 文件服务器", + Action: "在当前目录或指定目录启动 HTTP 文件服务器,方便局域网内共享文件。" + + "默认端口 8000,-p 可指定端口;--upload 启用上传功能", + Usage: "[目录] [-p 端口] [--upload]", + Variants: threePlatformBuiltins("net.http"), + }, + + // ----- disk additions ----- + { + ID: "disk.inode", + Group: "disk", + Summary: "查看 inode 使用情况", + Action: "显示文件系统的 inode 使用统计。inode 耗尽会导致无法创建新文件,即使磁盘空间充足。" + + "Linux/macOS: df -i;Windows 不支持(NTFS 无 inode 概念)", + Usage: "[路径]", + Variants: threePlatformBuiltins("disk.inode"), + }, + { + ID: "disk.check", + Group: "disk", + Summary: "一键磁盘健康检查", + Action: "综合检查磁盘健康状况:空间使用率、inode 使用率、大文件 TOP 5、大目录 TOP 5,并给出清理建议。" + + "一条命令完成磁盘排障", + Usage: "[路径] [--all]", + Variants: threePlatformBuiltins("disk.check"), + }, }} } diff --git a/internal/registry/registry_test.go b/internal/registry/registry_test.go index 689dd98..980e261 100644 --- a/internal/registry/registry_test.go +++ b/internal/registry/registry_test.go @@ -25,7 +25,7 @@ func TestBuiltinIDsStable(t *testing.T) { "docker.prunebuilder", "docker.prunevolumes", "docker.clearall", "docker.compose.up", "docker.compose.down", "docker.compose.ps", "docker.compose.logs", "diagnose", - "disk.usage", "net.pids", "net.ports", "proc.nohup", "proc.wait", "java.run", "git.retime", "pkg.list", "pkg.refreshindex", + "disk.usage", "net.pids", "net.ports", "proc.nohup", "proc.wait", "java.run", "git.retime", "git.time", "pkg.list", "pkg.refreshindex", "user.list", "user.grant", "user.revoke", "file.findbig", "file.findrecent", "file.findname", "svc.list", "svc.status", "svc.enable", "svc.disable", "svc.logs", @@ -39,6 +39,10 @@ func TestBuiltinIDsStable(t *testing.T) { "proc.tree", "file.empty", "user.info", + "pkg.install", "pkg.remove", "pkg.search", "pkg.info", + "archive.create", "archive.list", + "net.http", + "disk.inode", "disk.check", } if got := reg.IDs(); !reflect.DeepEqual(got, want) { t.Fatalf("IDs() =\n%v\nwant\n%v", got, want)