pqcheck 0.15.0 → 0.15.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -1
- package/bin/cipherwake-prompt-hook.js +111 -0
- package/bin/pqcheck.js +119 -8
- package/package.json +17 -8
package/README.md
CHANGED
|
@@ -27,7 +27,9 @@ The same scanner that powers [cipherwake.io](https://cipherwake.io), the browser
|
|
|
27
27
|
| `npx pqcheck onboard <domain>` | One command: scan → scaffold the GitHub Action → capture a vendor lockfile → set a baseline → commit + push. Zero copy-paste from docs. |
|
|
28
28
|
| **`npx pqcheck guard --domain <D> -- <cmd>`** 🆕 | **Deploy guard wrapper.** Wraps any deploy command. Runs `deploy-check` first; conditionally runs `<cmd>` based on `ship_decision`. Modes: `--gate-mode balanced` (default) / `advisory` / `strict`. ONE command instead of two — the strongest single artifact for AI-coder workflows because the AI never has to remember to chain check + deploy. |
|
|
29
29
|
| **`npx pqcheck protocol install`** 🆕 | **Opt-in installer** for the AI Coder Protocol — appends the pre-deploy verification rule to your `CLAUDE.md` / `.cursorrules` / `.aider.conf.yml` with explicit consent (Rule 17). One upfront question (auto / manual / no). Never silent writes. |
|
|
30
|
-
| **`npx pqcheck setup --auto --domain <D>`** 🆕 | **One-command full setup for every AI coder.** Installs (idempotently): GitHub Action workflow, AI Coder Protocol across all detected rules files (Claude / Cursor / Copilot / Aider / Windsurf / Continue / Cline / AGENTS.md) using fenced markers (`<!-- CIPHERWAKE_AI_CODER_PROTOCOL_START/END -->`), git pre-push hook, Claude Code statusLine +
|
|
30
|
+
| **`npx pqcheck setup --auto --domain <D>`** 🆕 | **One-command full setup for every AI coder.** Installs (idempotently): GitHub Action workflow, AI Coder Protocol across all detected rules files (Claude / Cursor / Copilot / Aider / Windsurf / Continue / Cline / AGENTS.md) using fenced markers (`<!-- CIPHERWAKE_AI_CODER_PROTOCOL_START/END -->`), git pre-push hook, Claude Code statusLine + 2 hooks (PostToolUse Bash + **UserPromptSubmit** ⓝ), per-repo `.cipherwake/last-status.json` for Cursor / Copilot / Continue to read as context. Skip flags available. Backups taken before any `~/.claude/settings.json` write. Audit trail at `~/.config/cipherwake/install-prefs.json`; install manifest at `~/.config/cipherwake/install-manifest.json`. |
|
|
31
|
+
| **`UserPromptSubmit` hook** (v0.15.1 ⓝ) | **Claude sees `ship_decision` before responding to every prompt.** When `pqcheck setup --auto` runs, it wires `cipherwake-prompt-hook` as a Claude Code UserPromptSubmit hook. On every user prompt, the hook injects `additionalContext` with the current scan's `ship_decision` IF it's `review`/`block` and the state is <24h old. Silent when state is missing, stale, or `pass`. Different timing from the PostToolUse chat-hook: this fires *before* Claude thinks (proactive), the chat-hook fires *after* a Bash command (reactive). |
|
|
32
|
+
| **Per-repo state file** `.cipherwake/last-status.json` (v0.15.1 ⓝ) | **Cursor / Copilot / Continue read this for workspace context.** Every `pqcheck` scan writes the same payload as the per-user file. Created by `setup --auto`; auto-added to `.gitignore` (per-developer state, not committable). Gives AI agents inside VS Code-family editors a repo-local artifact they pick up automatically when reading workspace files. |
|
|
31
33
|
| **`npx pqcheck setup --plan --domain <D>`** 🆕 | **Dry-run mode.** Prints every file change `--auto` would make (target paths + operation type: create / append-markered / deep-merge / backup-first) without writing anything. Run this first when you're not sure what `--auto` will touch. |
|
|
32
34
|
| **`npx pqcheck debug-network`** 🆕 | **Connectivity diagnostic.** Probes cipherwake.io API, homepage, crt.sh upstream, and the direct Vercel URL (bypassing Cloudflare). Reports HTTP status + timing per hop. Use when "scan hung" / "command not found" / corporate proxy issues come up — surfaces the actual broken hop with an actionable cause list. |
|
|
33
35
|
| **`--ai` flag** (any of the above) | **AI Coder Mode** (0.15.0). Three-layer output (banner / body / structured `CIPHERWAKE_AI_GUARD_RESULT` block) tuned for Claude Code / Cursor / Aider / Zed. Includes a `ship_decision=pass\|review\|block` field your AI coworker parses to decide whether to announce the deploy, ask you, or revert. See [/methodology/ai-coder-mode](https://cipherwake.io/methodology/ai-coder-mode). |
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// =============================================================================
|
|
3
|
+
// cipherwake-prompt-hook — Claude Code UserPromptSubmit hook (v0.15.1 parity)
|
|
4
|
+
// =============================================================================
|
|
5
|
+
// Fires BEFORE Claude responds to every user prompt. Injects the latest scan
|
|
6
|
+
// state from ~/.config/cipherwake/last-scan.json into Claude's context, so
|
|
7
|
+
// the AI sees ship_decision proactively (e.g., when the user says "ok deploy
|
|
8
|
+
// this", Claude already knows the trust posture).
|
|
9
|
+
//
|
|
10
|
+
// Different timing from cipherwake-chat-hook (PostToolUse Bash) — that one
|
|
11
|
+
// fires AFTER a tool runs and pushes a chat message reactively. This one
|
|
12
|
+
// fires BEFORE the model thinks, by injecting additionalContext via the
|
|
13
|
+
// hookSpecificOutput shape.
|
|
14
|
+
//
|
|
15
|
+
// Silent (no injection) when:
|
|
16
|
+
// • state file missing
|
|
17
|
+
// • state file > 24h old (don't anchor on stale data)
|
|
18
|
+
// • ship_decision === "pass" (no need to spam the model with good news)
|
|
19
|
+
//
|
|
20
|
+
// Wire-up via `pqcheck setup --auto` writes the entry to
|
|
21
|
+
// ~/.claude/settings.json under `hooks.UserPromptSubmit`.
|
|
22
|
+
// =============================================================================
|
|
23
|
+
|
|
24
|
+
import { readFileSync } from "node:fs";
|
|
25
|
+
import { join } from "node:path";
|
|
26
|
+
import { homedir } from "node:os";
|
|
27
|
+
|
|
28
|
+
const STATE_FILE = process.env.CIPHERWAKE_STATE_FILE
|
|
29
|
+
|| join(homedir(), ".config", "cipherwake", "last-scan.json");
|
|
30
|
+
|
|
31
|
+
const MAX_STATE_AGE_MS = 24 * 60 * 60 * 1000; // 24h — older than this, don't inject
|
|
32
|
+
|
|
33
|
+
function readStdin() {
|
|
34
|
+
return new Promise((resolve) => {
|
|
35
|
+
let data = "";
|
|
36
|
+
process.stdin.setEncoding("utf8");
|
|
37
|
+
process.stdin.on("data", (chunk) => (data += chunk));
|
|
38
|
+
process.stdin.on("end", () => resolve(data));
|
|
39
|
+
// If no stdin (manual invocation), resolve empty immediately
|
|
40
|
+
if (process.stdin.isTTY) resolve("");
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function silent() {
|
|
45
|
+
// Output nothing — Claude Code treats empty output as "no injection".
|
|
46
|
+
process.exit(0);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async function main() {
|
|
50
|
+
// Drain stdin (Claude Code sends a JSON event payload). We don't actually
|
|
51
|
+
// need the event content here — we just decide based on cached state.
|
|
52
|
+
try { await readStdin(); } catch { /* ignore */ }
|
|
53
|
+
|
|
54
|
+
let state;
|
|
55
|
+
try {
|
|
56
|
+
state = JSON.parse(readFileSync(STATE_FILE, "utf8"));
|
|
57
|
+
} catch {
|
|
58
|
+
silent();
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Freshness: only inject if the last scan is recent. Anchoring Claude on
|
|
63
|
+
// a week-old REVIEW state would be misleading after the user has likely
|
|
64
|
+
// already fixed the issue.
|
|
65
|
+
const writtenAt = state.written_at ? new Date(state.written_at).getTime() : 0;
|
|
66
|
+
if (!writtenAt || Date.now() - writtenAt > MAX_STATE_AGE_MS) {
|
|
67
|
+
silent();
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
// Only inject for non-pass states. Don't spam the model with good news on
|
|
72
|
+
// every prompt — Claude already trusts that no news is good news.
|
|
73
|
+
const shipDecision = String(state.ship_decision || "").toLowerCase();
|
|
74
|
+
if (shipDecision !== "review" && shipDecision !== "block") {
|
|
75
|
+
silent();
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const emoji = shipDecision === "block" ? "⛔" : "⚠";
|
|
80
|
+
const sevLabel = shipDecision === "block" ? "BLOCK" : "REVIEW";
|
|
81
|
+
const dbr = typeof state.score === "number" ? state.score.toFixed(1) : "?";
|
|
82
|
+
const grade = state.grade || "?";
|
|
83
|
+
const maxSev = String(state.max_severity || "").toUpperCase();
|
|
84
|
+
const top = state.top_issue || "—";
|
|
85
|
+
const ago = Math.floor((Date.now() - writtenAt) / 60000);
|
|
86
|
+
const ageStr = ago < 1 ? "just now" : ago < 60 ? `${ago}m ago` : `${Math.floor(ago / 60)}h ago`;
|
|
87
|
+
|
|
88
|
+
// Build the context-injection block. Brevity matters — this lands in every
|
|
89
|
+
// user prompt's context, so it should be a one-paragraph reminder, not a
|
|
90
|
+
// multi-screen status report.
|
|
91
|
+
const additionalContext =
|
|
92
|
+
`${emoji} Cipherwake — latest scan of ${state.domain || "configured domain"}: ship_decision=${shipDecision} ` +
|
|
93
|
+
`(${sevLabel}, DBR ${dbr} ${grade}, max ${maxSev}, last scanned ${ageStr}). ` +
|
|
94
|
+
`Top issue: ${top}. ` +
|
|
95
|
+
`Before announcing a deploy, run \`npx pqcheck deploy-check ${state.domain || "<domain>"} --ai\` to refresh. ` +
|
|
96
|
+
`If ship_decision is still ${shipDecision}, surface the change to the user per the AI Coder Protocol ` +
|
|
97
|
+
`(https://cipherwake.io/methodology/ai-coder-protocol) — don't auto-announce.`;
|
|
98
|
+
|
|
99
|
+
// Claude Code's UserPromptSubmit hook accepts hookSpecificOutput.additionalContext
|
|
100
|
+
// which is injected into the model's input on this turn. The hook returns
|
|
101
|
+
// synchronously; suppressOutput hides anything on stdout from the UI.
|
|
102
|
+
process.stdout.write(JSON.stringify({
|
|
103
|
+
hookSpecificOutput: {
|
|
104
|
+
hookEventName: "UserPromptSubmit",
|
|
105
|
+
additionalContext,
|
|
106
|
+
},
|
|
107
|
+
suppressOutput: true,
|
|
108
|
+
}));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
main().catch(() => silent());
|
package/bin/pqcheck.js
CHANGED
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
})();
|
|
25
25
|
|
|
26
26
|
const API_BASE = process.env.PQCHECK_API_BASE || "https://cipherwake.io";
|
|
27
|
-
const VERSION = "0.15.
|
|
27
|
+
const VERSION = "0.15.1";
|
|
28
28
|
|
|
29
29
|
// API-key support — paid tiers (Starter $29 / Growth $79 / Scale $199) get
|
|
30
30
|
// per-account monthly quotas instead of the per-IP rate limit. Set via:
|
|
@@ -633,18 +633,39 @@ function formatAiFooterBlock(fields) {
|
|
|
633
633
|
}
|
|
634
634
|
|
|
635
635
|
// Persist last-scan state to ~/.config/cipherwake/last-scan.json.
|
|
636
|
-
// Feeds the
|
|
637
|
-
// persistent ambient state in their AI coder's
|
|
638
|
-
//
|
|
636
|
+
// Feeds the cipherwake-statusline + cipherwake-prompt-hook + cipherwake-chat-hook
|
|
637
|
+
// scripts so users get persistent ambient state in their AI coder's surfaces.
|
|
638
|
+
//
|
|
639
|
+
// v0.15.1 (2026-05-22): ALSO writes a per-repo state file at
|
|
640
|
+
// .cipherwake/last-status.json IF that directory exists in cwd (created by
|
|
641
|
+
// `pqcheck setup --auto`). This gives Cursor / Copilot / Continue / Cline
|
|
642
|
+
// agents a read-on-demand surface inside the repo — they see the latest
|
|
643
|
+
// trust posture for the customer's primary domain when scanning repo state.
|
|
644
|
+
//
|
|
645
|
+
// Best-effort — never throws (a write failure doesn't break the scan).
|
|
639
646
|
async function writeLastScanFile(payload) {
|
|
640
647
|
try {
|
|
641
648
|
const os = await import("node:os");
|
|
642
649
|
const path = await import("node:path");
|
|
643
650
|
const fs = await import("node:fs/promises");
|
|
644
|
-
const
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
651
|
+
const enriched = { ...payload, written_at: new Date().toISOString() };
|
|
652
|
+
|
|
653
|
+
// Per-user state file (primary, always written)
|
|
654
|
+
const userDir = path.join(os.homedir(), ".config", "cipherwake");
|
|
655
|
+
await fs.mkdir(userDir, { recursive: true });
|
|
656
|
+
await fs.writeFile(path.join(userDir, "last-scan.json"), JSON.stringify(enriched, null, 2));
|
|
657
|
+
|
|
658
|
+
// Per-repo state file (secondary, only if .cipherwake/ exists in cwd
|
|
659
|
+
// — i.e., this repo went through `pqcheck setup --auto`). Gives Cursor/
|
|
660
|
+
// Copilot/Continue/Cline agents a repo-local artifact they pick up
|
|
661
|
+
// automatically when reading workspace state.
|
|
662
|
+
const repoDir = path.join(process.cwd(), ".cipherwake");
|
|
663
|
+
try {
|
|
664
|
+
await fs.access(repoDir);
|
|
665
|
+
await fs.writeFile(path.join(repoDir, "last-status.json"), JSON.stringify(enriched, null, 2));
|
|
666
|
+
} catch {
|
|
667
|
+
// .cipherwake/ doesn't exist here — that's fine, user didn't run setup --auto in this repo
|
|
668
|
+
}
|
|
648
669
|
} catch {
|
|
649
670
|
// best-effort
|
|
650
671
|
}
|
|
@@ -4991,6 +5012,96 @@ async function runSetupCommand(args) {
|
|
|
4991
5012
|
}
|
|
4992
5013
|
}
|
|
4993
5014
|
|
|
5015
|
+
// -------------------------------------------------------------------------
|
|
5016
|
+
// Component 4c: Claude Code prompt-hook (UserPromptSubmit → cipherwake-prompt-hook)
|
|
5017
|
+
// v0.15.1 — pinnedai-parity item. Injects ship_decision into Claude's
|
|
5018
|
+
// context BEFORE Claude responds to every user prompt. Different timing
|
|
5019
|
+
// from 4b: chat-hook fires AFTER a tool ran (reactive), prompt-hook fires
|
|
5020
|
+
// BEFORE Claude responds (proactive). Silent when state is missing / stale
|
|
5021
|
+
// / ship_decision=pass (no spam).
|
|
5022
|
+
// -------------------------------------------------------------------------
|
|
5023
|
+
if (!skipStatusline) {
|
|
5024
|
+
const settingsPath = path.join(os.homedir(), ".claude", "settings.json");
|
|
5025
|
+
try {
|
|
5026
|
+
let settings = {};
|
|
5027
|
+
let existed = false;
|
|
5028
|
+
try {
|
|
5029
|
+
const raw = await fs.readFile(settingsPath, "utf8");
|
|
5030
|
+
settings = JSON.parse(raw);
|
|
5031
|
+
existed = true;
|
|
5032
|
+
} catch { /* will create */ }
|
|
5033
|
+
settings.hooks = settings.hooks || {};
|
|
5034
|
+
settings.hooks.UserPromptSubmit = settings.hooks.UserPromptSubmit || [];
|
|
5035
|
+
|
|
5036
|
+
const cipherwakeHookCmd = "npx cipherwake-prompt-hook";
|
|
5037
|
+
const alreadyInstalled = settings.hooks.UserPromptSubmit.some(
|
|
5038
|
+
(entry) => Array.isArray(entry?.hooks) && entry.hooks.some(
|
|
5039
|
+
(h) => h?.type === "command" && typeof h?.command === "string" && h.command.includes("cipherwake-prompt-hook"),
|
|
5040
|
+
),
|
|
5041
|
+
);
|
|
5042
|
+
|
|
5043
|
+
if (alreadyInstalled) {
|
|
5044
|
+
console.log(color("dim", ` ⊝ prompt-hook already configured in ~/.claude/settings.json UserPromptSubmit — skipping`));
|
|
5045
|
+
installSummary.push({ component: "Claude Code prompt-hook", path: settingsPath, status: "skipped-already-present" });
|
|
5046
|
+
} else {
|
|
5047
|
+
const backupPath = existed ? await backupSettingsJson(settingsPath) : null;
|
|
5048
|
+
if (backupPath) console.log(color("dim", ` backup: ${backupPath}`));
|
|
5049
|
+
settings.hooks.UserPromptSubmit.push({ hooks: [{ type: "command", command: cipherwakeHookCmd }] });
|
|
5050
|
+
await fs.mkdir(path.dirname(settingsPath), { recursive: true });
|
|
5051
|
+
await fs.writeFile(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf8");
|
|
5052
|
+
console.log(color("green", ` ✓ added prompt-hook (UserPromptSubmit) → ~/.claude/settings.json`));
|
|
5053
|
+
console.log(color("dim", ` Claude will see latest ship_decision in context on every prompt (when REVIEW/BLOCK)`));
|
|
5054
|
+
installSummary.push({ component: "Claude Code prompt-hook", path: settingsPath, status: existed ? "installed-updated" : "installed-created", backup: backupPath });
|
|
5055
|
+
}
|
|
5056
|
+
} catch (err) {
|
|
5057
|
+
console.log(color("red", ` ✗ prompt-hook install failed: ${err.message}`));
|
|
5058
|
+
installSummary.push({ component: "Claude Code prompt-hook", status: "failed", error: String(err?.message || err) });
|
|
5059
|
+
}
|
|
5060
|
+
}
|
|
5061
|
+
|
|
5062
|
+
// -------------------------------------------------------------------------
|
|
5063
|
+
// Component 4d: Per-repo state directory (.cipherwake/) for Cursor / Copilot
|
|
5064
|
+
// v0.15.1 — pinnedai-parity item. Cursor/Copilot/Continue/Cline read repo
|
|
5065
|
+
// state for context. Creating .cipherwake/ in the repo gives them a
|
|
5066
|
+
// read-on-demand surface that subsequent `pqcheck` runs (via the
|
|
5067
|
+
// writeLastScanFile path) populate with the latest scan state. Also adds
|
|
5068
|
+
// .cipherwake/ to .gitignore if not already there — per-developer state,
|
|
5069
|
+
// not committable.
|
|
5070
|
+
// -------------------------------------------------------------------------
|
|
5071
|
+
if (!skipStatusline) {
|
|
5072
|
+
try {
|
|
5073
|
+
const repoStateDir = path.join(process.cwd(), ".cipherwake");
|
|
5074
|
+
await fs.mkdir(repoStateDir, { recursive: true });
|
|
5075
|
+
// Write an initial placeholder so the file exists immediately. Subsequent
|
|
5076
|
+
// scans via writeLastScanFile will overwrite with real data.
|
|
5077
|
+
const placeholderPath = path.join(repoStateDir, "last-status.json");
|
|
5078
|
+
try {
|
|
5079
|
+
await fs.access(placeholderPath);
|
|
5080
|
+
// Already exists — preserve it.
|
|
5081
|
+
} catch {
|
|
5082
|
+
await fs.writeFile(placeholderPath, JSON.stringify({
|
|
5083
|
+
domain,
|
|
5084
|
+
ship_decision: "unknown",
|
|
5085
|
+
note: "Initial placeholder — run `npx pqcheck deploy-check " + domain + " --ai` to populate",
|
|
5086
|
+
written_at: new Date().toISOString(),
|
|
5087
|
+
}, null, 2));
|
|
5088
|
+
}
|
|
5089
|
+
// Add .cipherwake/ to .gitignore if missing (don't commit per-developer state).
|
|
5090
|
+
const gitignorePath = path.join(process.cwd(), ".gitignore");
|
|
5091
|
+
let gitignore = "";
|
|
5092
|
+
try { gitignore = await fs.readFile(gitignorePath, "utf8"); } catch { /* may not exist */ }
|
|
5093
|
+
if (!/^\.cipherwake\/?\s*$/m.test(gitignore)) {
|
|
5094
|
+
const appended = gitignore + (gitignore.endsWith("\n") || gitignore.length === 0 ? "" : "\n") + "\n# Cipherwake per-developer scan state (read-on-demand by AI coders)\n.cipherwake/\n";
|
|
5095
|
+
await fs.writeFile(gitignorePath, appended);
|
|
5096
|
+
}
|
|
5097
|
+
console.log(color("green", ` ✓ created .cipherwake/last-status.json (Cursor/Copilot/Continue read this for context)`));
|
|
5098
|
+
installSummary.push({ component: "Per-repo state file", path: placeholderPath, status: "installed" });
|
|
5099
|
+
} catch (err) {
|
|
5100
|
+
console.log(color("red", ` ✗ per-repo state install failed: ${err.message}`));
|
|
5101
|
+
installSummary.push({ component: "Per-repo state file", status: "failed", error: String(err?.message || err) });
|
|
5102
|
+
}
|
|
5103
|
+
}
|
|
5104
|
+
|
|
4994
5105
|
// -------------------------------------------------------------------------
|
|
4995
5106
|
// Component 5: VS Code / Cursor extension (via `code` CLI if available)
|
|
4996
5107
|
// -------------------------------------------------------------------------
|
package/package.json
CHANGED
|
@@ -1,21 +1,29 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pqcheck",
|
|
3
|
-
"version": "0.15.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.15.1",
|
|
4
|
+
"description": "Deploy gate for AI-coded web apps. `pqcheck deploy-check --ai` returns ship_decision=pass|review|block for Claude Code / Cursor / Copilot / Aider to gate deploys before they ship. Anonymous, no signup, free for first use.",
|
|
5
5
|
"keywords": [
|
|
6
|
-
"
|
|
7
|
-
"
|
|
6
|
+
"ai-coder",
|
|
7
|
+
"claude-code",
|
|
8
|
+
"cursor",
|
|
9
|
+
"copilot",
|
|
10
|
+
"aider",
|
|
11
|
+
"deploy-gate",
|
|
12
|
+
"deploy-check",
|
|
13
|
+
"ai-coder-mode",
|
|
14
|
+
"ship-decision",
|
|
15
|
+
"deploy-guard",
|
|
16
|
+
"ci",
|
|
8
17
|
"security",
|
|
9
18
|
"tls",
|
|
10
19
|
"ssl",
|
|
11
20
|
"scanner",
|
|
21
|
+
"post-quantum",
|
|
12
22
|
"harvest-now-decrypt-later",
|
|
13
23
|
"hndl",
|
|
14
24
|
"blast-radius",
|
|
15
25
|
"pqc",
|
|
16
|
-
"quantum"
|
|
17
|
-
"crypto-audit",
|
|
18
|
-
"crypto-inventory"
|
|
26
|
+
"quantum"
|
|
19
27
|
],
|
|
20
28
|
"homepage": "https://cipherwake.io",
|
|
21
29
|
"bugs": "https://cipherwake.io",
|
|
@@ -33,7 +41,8 @@
|
|
|
33
41
|
"bin": {
|
|
34
42
|
"pqcheck": "./bin/pqcheck.js",
|
|
35
43
|
"cipherwake-statusline": "./bin/cipherwake-statusline.js",
|
|
36
|
-
"cipherwake-chat-hook": "./bin/cipherwake-chat-hook.js"
|
|
44
|
+
"cipherwake-chat-hook": "./bin/cipherwake-chat-hook.js",
|
|
45
|
+
"cipherwake-prompt-hook": "./bin/cipherwake-prompt-hook.js"
|
|
37
46
|
},
|
|
38
47
|
"files": [
|
|
39
48
|
"bin/",
|