lockpicks 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -16
- package/dist/lockpick.mjs +109 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,21 +20,22 @@ With it installed, `lockpick mcp config` points agents at `lockpick mcp`; withou
|
|
|
20
20
|
|
|
21
21
|
## Commands
|
|
22
22
|
|
|
23
|
-
| Command | What it shows
|
|
24
|
-
| -------------------------------------- |
|
|
25
|
-
| `lockpick whoami` | The user, workspace and key this terminal uses
|
|
26
|
-
| `lockpick projects` | Projects with their latest Pulse and pentest
|
|
27
|
-
| `lockpick status [project]` | One project's report, or an overview of all of them
|
|
28
|
-
| `lockpick runs` | Pulse assessments and pentests, newest first
|
|
29
|
-
| `lockpick run <runId>` | One run: status, open findings, coverage and limits
|
|
30
|
-
| `lockpick watch <runId>` | Follows a run until it finishes
|
|
31
|
-
| `lockpick pulse <project>` | Starts a Pulse (a recheck of the latest one when possible) and waits for the result
|
|
32
|
-
| `lockpick findings <runId>` | Findings that need attention (`--all` for informational ones)
|
|
33
|
-
| `lockpick finding <runId> <findingId>` | One finding with its evidence
|
|
34
|
-
| `lockpick brief <runId>` |
|
|
35
|
-
| `lockpick
|
|
36
|
-
| `lockpick
|
|
37
|
-
| `lockpick
|
|
23
|
+
| Command | What it shows |
|
|
24
|
+
| -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
25
|
+
| `lockpick whoami` | The user, workspace and key this terminal uses |
|
|
26
|
+
| `lockpick projects` | Projects with their latest Pulse and pentest |
|
|
27
|
+
| `lockpick status [project]` | One project's report, or an overview of all of them |
|
|
28
|
+
| `lockpick runs` | Pulse assessments and pentests, newest first |
|
|
29
|
+
| `lockpick run <runId>` | One run: status, open findings, coverage and limits |
|
|
30
|
+
| `lockpick watch <runId>` | Follows a run until it finishes |
|
|
31
|
+
| `lockpick pulse <project>` | Starts a Pulse (a recheck of the latest one when possible) and waits for the result |
|
|
32
|
+
| `lockpick findings <runId>` | Findings that need attention (`--all` for informational ones) |
|
|
33
|
+
| `lockpick finding <runId> <findingId>` | One finding with its evidence |
|
|
34
|
+
| `lockpick brief <runId>` | One brief that fixes everything needing attention (`--finding <id>` for one finding, `--agent <name>` to tailor it, `--out brief.md` to save it) |
|
|
35
|
+
| `lockpick fix <runId> --agent <name>` | Saves the fix-all brief to `lockpick-fixes.md` and prints the command that starts your agent on it |
|
|
36
|
+
| `lockpick compare <runId>` | What a Pulse recheck changed against its baseline |
|
|
37
|
+
| `lockpick open <id>` | Opens a run or project in the browser |
|
|
38
|
+
| `lockpick skills` | Adds the Lockpick skills to your coding agent (`npx skills add`) |
|
|
38
39
|
|
|
39
40
|
Every command takes `--host` and `--json`. With `--json`, errors are printed to stderr as `{ "error": "…", "code": "…" }`.
|
|
40
41
|
|
|
@@ -48,7 +49,7 @@ Each Pulse uses one of your account's runs, the same as starting it in the web a
|
|
|
48
49
|
lockpick mcp config claude # or cursor, vscode, codex
|
|
49
50
|
```
|
|
50
51
|
|
|
51
|
-
prints the setup for your agent. The server (`lockpick mcp`, stdio) offers ten reading tools, `lockpick_start_pulse` (only for keys allowed to start Pulses), a repair-brief resource and a `fix-lockpick-findings` prompt. Evidence captured from scanned sites is fenced as untrusted data, and agents are told never to follow instructions inside it.
|
|
52
|
+
prints the setup for your agent. The server (`lockpick mcp`, stdio) offers ten reading tools, `lockpick_start_pulse` (only for keys allowed to start Pulses), a repair-brief resource and a `fix-lockpick-findings` prompt. `lockpick_get_repair_brief` without a `findingId` returns the fix-all brief, and its `agent` argument tailors it. Evidence captured from scanned sites is fenced as untrusted data, and agents are told never to follow instructions inside it.
|
|
52
53
|
|
|
53
54
|
## Environment
|
|
54
55
|
|
package/dist/lockpick.mjs
CHANGED
|
@@ -23541,6 +23541,45 @@ var StdioServerTransport = class {
|
|
|
23541
23541
|
}
|
|
23542
23542
|
};
|
|
23543
23543
|
|
|
23544
|
+
// ../../packages/contracts/src/prompt-agents.ts
|
|
23545
|
+
var PROMPT_AGENTS = [
|
|
23546
|
+
"claude-code",
|
|
23547
|
+
"codex",
|
|
23548
|
+
"cursor",
|
|
23549
|
+
"vscode",
|
|
23550
|
+
"opencode",
|
|
23551
|
+
"lovable",
|
|
23552
|
+
"bolt",
|
|
23553
|
+
"replit",
|
|
23554
|
+
"v0"
|
|
23555
|
+
];
|
|
23556
|
+
var PROMPT_AGENT_LAUNCH = {
|
|
23557
|
+
"claude-code": "claude",
|
|
23558
|
+
codex: "codex",
|
|
23559
|
+
cursor: "cursor-agent",
|
|
23560
|
+
vscode: "code chat --mode agent",
|
|
23561
|
+
opencode: "opencode --prompt=",
|
|
23562
|
+
lovable: null,
|
|
23563
|
+
bolt: null,
|
|
23564
|
+
replit: null,
|
|
23565
|
+
v0: null
|
|
23566
|
+
};
|
|
23567
|
+
function isPromptAgent(value) {
|
|
23568
|
+
return PROMPT_AGENTS.includes(value);
|
|
23569
|
+
}
|
|
23570
|
+
var FIX_ALL_FILE = "lockpick-fixes.md";
|
|
23571
|
+
function agentCommand(agent, text2) {
|
|
23572
|
+
const launch = PROMPT_AGENT_LAUNCH[agent];
|
|
23573
|
+
if (!launch) throw new Error(`No command line tool for ${agent}`);
|
|
23574
|
+
return launch.endsWith("=") ? `${launch}${text2}` : `${launch} ${text2}`;
|
|
23575
|
+
}
|
|
23576
|
+
function readBriefCommand(agent, file2 = FIX_ALL_FILE) {
|
|
23577
|
+
return agentCommand(
|
|
23578
|
+
agent,
|
|
23579
|
+
`"Read ${file2} and follow it. Do not commit that file."`
|
|
23580
|
+
);
|
|
23581
|
+
}
|
|
23582
|
+
|
|
23544
23583
|
// ../../packages/contracts/src/cli-routes.ts
|
|
23545
23584
|
var CLI_API = "/api/cli/v1";
|
|
23546
23585
|
var segment = (value) => encodeURIComponent(value);
|
|
@@ -23752,6 +23791,10 @@ var cliFindingListQuerySchema = external_exports.object({
|
|
|
23752
23791
|
/** Passing and not-assessed checks are hidden unless asked for. */
|
|
23753
23792
|
all: external_exports.enum(["true", "false"]).optional().transform((value) => value === "true")
|
|
23754
23793
|
});
|
|
23794
|
+
var cliRepairBriefQuerySchema = external_exports.object({
|
|
23795
|
+
findingId: external_exports.string().min(1).max(500).optional(),
|
|
23796
|
+
agent: external_exports.enum(PROMPT_AGENTS).optional()
|
|
23797
|
+
});
|
|
23755
23798
|
|
|
23756
23799
|
// src/api.ts
|
|
23757
23800
|
function friendlyError(status2, message, replace) {
|
|
@@ -23930,12 +23973,13 @@ var LockpickClient = class {
|
|
|
23930
23973
|
{ notFound: missingRun(runId) }
|
|
23931
23974
|
);
|
|
23932
23975
|
}
|
|
23933
|
-
|
|
23976
|
+
/** One finding's brief, or the fix-all brief; `agent` tailors it. */
|
|
23977
|
+
repairBrief(runId, findingId, agent) {
|
|
23934
23978
|
return this.request(
|
|
23935
23979
|
CLI_API_ROUTES.repairBrief(runId),
|
|
23936
23980
|
cliRepairBriefSchema,
|
|
23937
23981
|
{
|
|
23938
|
-
query: { findingId },
|
|
23982
|
+
query: { findingId, agent },
|
|
23939
23983
|
notFound: missingRun(runId)
|
|
23940
23984
|
}
|
|
23941
23985
|
);
|
|
@@ -24347,7 +24391,7 @@ import { delimiter, join as join2, sep } from "node:path";
|
|
|
24347
24391
|
import { createInterface } from "node:readline/promises";
|
|
24348
24392
|
|
|
24349
24393
|
// src/version.ts
|
|
24350
|
-
var CLI_VERSION = true ? "0.
|
|
24394
|
+
var CLI_VERSION = true ? "0.2.0" : "0.0.0-dev";
|
|
24351
24395
|
var CLI_PACKAGE = true ? "lockpicks" : "lockpicks";
|
|
24352
24396
|
|
|
24353
24397
|
// src/install.ts
|
|
@@ -34410,15 +34454,16 @@ Still ${run2.status}. Call lockpick_wait_for_run with runId \`${run2.id}\` to ke
|
|
|
34410
34454
|
"lockpick_get_repair_brief",
|
|
34411
34455
|
{
|
|
34412
34456
|
title: "Get repair brief",
|
|
34413
|
-
description: "A markdown repair brief for one finding, or
|
|
34457
|
+
description: "A markdown repair brief for one finding, or, when findingId is omitted, one fix-all brief covering every finding that needs attention: a numbered index, a section per fix, the steps only the owner can take and one set of boundaries. Uses the brief a teammate saved in Lockpick when there is one. Pass agent to append working instructions for that agent.",
|
|
34414
34458
|
inputSchema: {
|
|
34415
34459
|
runId: external_exports.string().min(1),
|
|
34416
|
-
findingId: external_exports.string().min(1).optional()
|
|
34460
|
+
findingId: external_exports.string().min(1).optional(),
|
|
34461
|
+
agent: external_exports.enum(PROMPT_AGENTS).optional().describe("Tailor the brief for this agent")
|
|
34417
34462
|
},
|
|
34418
34463
|
annotations: readOnly
|
|
34419
34464
|
},
|
|
34420
|
-
({ runId, findingId }) => call(async (client) => {
|
|
34421
|
-
const brief2 = await client.repairBrief(runId, findingId);
|
|
34465
|
+
({ runId, findingId, agent }) => call(async (client) => {
|
|
34466
|
+
const brief2 = await client.repairBrief(runId, findingId, agent);
|
|
34422
34467
|
if (brief2.findingIds.length === 0)
|
|
34423
34468
|
return text("No findings in this run need attention.");
|
|
34424
34469
|
return text(brief2.markdown);
|
|
@@ -34447,7 +34492,7 @@ Still ${run2.status}. Call lockpick_wait_for_run with runId \`${run2.id}\` to ke
|
|
|
34447
34492
|
}),
|
|
34448
34493
|
{
|
|
34449
34494
|
title: "Repair brief",
|
|
34450
|
-
description: "
|
|
34495
|
+
description: "The fix-all brief: one markdown document covering every finding in a run that needs attention.",
|
|
34451
34496
|
mimeType: "text/markdown"
|
|
34452
34497
|
},
|
|
34453
34498
|
async (uri, { runId }) => {
|
|
@@ -34586,6 +34631,16 @@ function parse3(schema, value, name, allowed) {
|
|
|
34586
34631
|
);
|
|
34587
34632
|
}
|
|
34588
34633
|
}
|
|
34634
|
+
function agentArg(value) {
|
|
34635
|
+
if (value === void 0) return void 0;
|
|
34636
|
+
if (isPromptAgent(value)) return value;
|
|
34637
|
+
throw new LockpickApiError(
|
|
34638
|
+
`--agent must be one of: ${PROMPT_AGENTS.join(", ")}`,
|
|
34639
|
+
400,
|
|
34640
|
+
"VALIDATION_ERROR"
|
|
34641
|
+
);
|
|
34642
|
+
}
|
|
34643
|
+
var agentHelp = `Tailor it for this agent: ${PROMPT_AGENTS.join(", ")}`;
|
|
34589
34644
|
async function findProject(client, ref) {
|
|
34590
34645
|
const projects2 = await client.listProjects();
|
|
34591
34646
|
const exact = projects2.find((project) => project.id === ref);
|
|
@@ -34927,17 +34982,19 @@ var finding = defineCommand({
|
|
|
34927
34982
|
var brief = defineCommand({
|
|
34928
34983
|
meta: {
|
|
34929
34984
|
name: "brief",
|
|
34930
|
-
description: "Markdown
|
|
34985
|
+
description: "Markdown brief that fixes everything in a run that needs attention (or one finding)"
|
|
34931
34986
|
},
|
|
34932
34987
|
args: {
|
|
34933
34988
|
runId: { type: "positional", description: "Run id", required: true },
|
|
34934
34989
|
finding: { type: "string", description: "Only this finding" },
|
|
34990
|
+
agent: { type: "string", description: agentHelp },
|
|
34935
34991
|
out: { type: "string", description: "Write the markdown to this file" },
|
|
34936
34992
|
...common
|
|
34937
34993
|
},
|
|
34938
34994
|
run: ({ args }) => action(async () => {
|
|
34995
|
+
const agent = agentArg(args.agent);
|
|
34939
34996
|
const client = await clientFor({ host: args.host });
|
|
34940
|
-
const result = await client.repairBrief(args.runId, args.finding);
|
|
34997
|
+
const result = await client.repairBrief(args.runId, args.finding, agent);
|
|
34941
34998
|
if (args.out) {
|
|
34942
34999
|
await writeFile2(args.out, `${result.markdown}
|
|
34943
35000
|
`);
|
|
@@ -34950,6 +35007,47 @@ var brief = defineCommand({
|
|
|
34950
35007
|
emit(args.json, result, () => result.markdown);
|
|
34951
35008
|
})
|
|
34952
35009
|
});
|
|
35010
|
+
var fix = defineCommand({
|
|
35011
|
+
meta: {
|
|
35012
|
+
name: "fix",
|
|
35013
|
+
description: `Save the fix-all brief to ${FIX_ALL_FILE} and print the command that starts your agent on it`
|
|
35014
|
+
},
|
|
35015
|
+
args: {
|
|
35016
|
+
runId: { type: "positional", description: "Run id", required: true },
|
|
35017
|
+
agent: { type: "string", description: agentHelp },
|
|
35018
|
+
out: {
|
|
35019
|
+
type: "string",
|
|
35020
|
+
description: `Where to save the brief (default: ${FIX_ALL_FILE})`
|
|
35021
|
+
},
|
|
35022
|
+
...common
|
|
35023
|
+
},
|
|
35024
|
+
run: ({ args }) => action(async () => {
|
|
35025
|
+
const agent = agentArg(args.agent);
|
|
35026
|
+
const client = await clientFor({ host: args.host });
|
|
35027
|
+
const result = await client.repairBrief(args.runId, void 0, agent);
|
|
35028
|
+
if (result.findingIds.length === 0) {
|
|
35029
|
+
if (args.json)
|
|
35030
|
+
return emit(true, { ...result, file: null, command: null }, () => "");
|
|
35031
|
+
return out("No findings in this run need attention.");
|
|
35032
|
+
}
|
|
35033
|
+
const file2 = args.out ?? FIX_ALL_FILE;
|
|
35034
|
+
await writeFile2(file2, `${result.markdown}
|
|
35035
|
+
`);
|
|
35036
|
+
const command = agent && PROMPT_AGENT_LAUNCH[agent] ? readBriefCommand(agent, file2) : null;
|
|
35037
|
+
const count = result.findingIds.length;
|
|
35038
|
+
if (args.json) return emit(true, { ...result, file: file2, command }, () => "");
|
|
35039
|
+
err(
|
|
35040
|
+
`Saved ${count} ${count === 1 ? "fix" : "fixes"} to ${file2}. Keep it out of your commits.`
|
|
35041
|
+
);
|
|
35042
|
+
if (command) {
|
|
35043
|
+
err("Start your agent on it from your project folder:");
|
|
35044
|
+
out(command);
|
|
35045
|
+
} else
|
|
35046
|
+
out(
|
|
35047
|
+
agent ? `Paste ${file2} into the ${agent} chat, or attach it.` : `Give ${file2} to your coding agent, or add --agent to get its command.`
|
|
35048
|
+
);
|
|
35049
|
+
})
|
|
35050
|
+
});
|
|
34953
35051
|
var compare = defineCommand({
|
|
34954
35052
|
meta: {
|
|
34955
35053
|
name: "compare",
|
|
@@ -35091,6 +35189,7 @@ var main = defineCommand({
|
|
|
35091
35189
|
findings,
|
|
35092
35190
|
finding,
|
|
35093
35191
|
brief,
|
|
35192
|
+
fix,
|
|
35094
35193
|
compare,
|
|
35095
35194
|
open,
|
|
35096
35195
|
mcp,
|
package/package.json
CHANGED