@mrciphersmith/keryx 0.3.67 → 0.3.73
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 +36 -8
- package/dist/cli.js +8691 -3173
- package/dist/core.js +90 -14
- package/package.json +1 -1
- package/src/gdgraph/service.ts +5 -0
- package/src/gdskills/bundled/skills/planning/interviewer/SKILL.md +11 -13
package/dist/core.js
CHANGED
|
@@ -6592,6 +6592,40 @@ var init_read_source = __esm(() => {
|
|
|
6592
6592
|
init_contained_path();
|
|
6593
6593
|
});
|
|
6594
6594
|
|
|
6595
|
+
// src/security/secret-shape.ts
|
|
6596
|
+
function isIdentifier(run) {
|
|
6597
|
+
const parts = run.match(RUN_PARTS) ?? [];
|
|
6598
|
+
if (parts.join("") !== run)
|
|
6599
|
+
return false;
|
|
6600
|
+
if (parts.filter((part) => /\d/.test(part)).length > 2)
|
|
6601
|
+
return false;
|
|
6602
|
+
return parts.every((part, index) => {
|
|
6603
|
+
if (/\d/.test(part))
|
|
6604
|
+
return part.length <= 3;
|
|
6605
|
+
if (/[-_]/.test(part))
|
|
6606
|
+
return true;
|
|
6607
|
+
return part.length >= 3 || /\d/.test(parts[index + 1] ?? "");
|
|
6608
|
+
});
|
|
6609
|
+
}
|
|
6610
|
+
function isSecretRun(run) {
|
|
6611
|
+
return /[a-z]/.test(run) && /[A-Z]/.test(run) && /\d/.test(run) && !isIdentifier(run);
|
|
6612
|
+
}
|
|
6613
|
+
function looksLikeSecret(text) {
|
|
6614
|
+
if (BOT_TOKEN_SHAPE.test(text))
|
|
6615
|
+
return true;
|
|
6616
|
+
for (const run of text.match(TOKEN_RUN) ?? []) {
|
|
6617
|
+
if (isSecretRun(run))
|
|
6618
|
+
return true;
|
|
6619
|
+
}
|
|
6620
|
+
return false;
|
|
6621
|
+
}
|
|
6622
|
+
var BOT_TOKEN_SHAPE, TOKEN_RUN, RUN_PARTS;
|
|
6623
|
+
var init_secret_shape = __esm(() => {
|
|
6624
|
+
BOT_TOKEN_SHAPE = /\d{6,}:[A-Za-z0-9_-]{30,}/;
|
|
6625
|
+
TOKEN_RUN = /[A-Za-z0-9_-]{32,}|[A-Za-z0-9+/]{40,}={0,2}/g;
|
|
6626
|
+
RUN_PARTS = /[A-Z][a-z]+|[a-z]+|[A-Z]+(?![a-z])|\d+|[-_]/g;
|
|
6627
|
+
});
|
|
6628
|
+
|
|
6595
6629
|
// src/security/credential-shape.ts
|
|
6596
6630
|
function isDeniedForMcpChild(name, value) {
|
|
6597
6631
|
if (value !== undefined && CREDENTIAL_IN_VALUE_RE.test(value))
|
|
@@ -9817,7 +9851,7 @@ var init_skill_length_ceilings = __esm(() => {
|
|
|
9817
9851
|
"planning/docpack-orchestrator": 172,
|
|
9818
9852
|
"planning/docpack-review": 92,
|
|
9819
9853
|
"planning/interview": 209,
|
|
9820
|
-
"planning/interviewer":
|
|
9854
|
+
"planning/interviewer": 129,
|
|
9821
9855
|
"planning/patterns-researcher": 254,
|
|
9822
9856
|
"planning/planner": 208,
|
|
9823
9857
|
"planning/prd-creator": 210,
|
|
@@ -15814,6 +15848,7 @@ __export(exports_service, {
|
|
|
15814
15848
|
isDeniedForMcpChild: () => isDeniedForMcpChild,
|
|
15815
15849
|
isEntropyBackendEnabled: () => isEntropyBackendEnabled,
|
|
15816
15850
|
loadSecurityConfig: () => loadSecurityConfig,
|
|
15851
|
+
looksLikeSecret: () => looksLikeSecret,
|
|
15817
15852
|
looksSecretShaped: () => looksSecretShaped,
|
|
15818
15853
|
looksSecretShapedIn: () => looksSecretShapedIn,
|
|
15819
15854
|
memoizeResolved: () => memoizeResolved,
|
|
@@ -16077,6 +16112,7 @@ var init_service2 = __esm(() => {
|
|
|
16077
16112
|
init_secrets();
|
|
16078
16113
|
init_entropy();
|
|
16079
16114
|
init_incidents();
|
|
16115
|
+
init_secret_shape();
|
|
16080
16116
|
init_entropy_gate();
|
|
16081
16117
|
init_credential_shape();
|
|
16082
16118
|
init_audit_harness();
|
|
@@ -28951,7 +28987,8 @@ __export(exports_service5, {
|
|
|
28951
28987
|
UnknownGraphTargetError: () => UnknownGraphTargetError,
|
|
28952
28988
|
buildAffectedReport: () => buildAffectedReport,
|
|
28953
28989
|
checkGraphStaleness: () => checkGraphStaleness,
|
|
28954
|
-
createGdgraphService: () => createGdgraphService
|
|
28990
|
+
createGdgraphService: () => createGdgraphService,
|
|
28991
|
+
estimateTokens: () => estimateTokens2
|
|
28955
28992
|
});
|
|
28956
28993
|
|
|
28957
28994
|
// src/gdgraph/build.ts
|
|
@@ -37391,7 +37428,7 @@ function normalizeFwkResult(result) {
|
|
|
37391
37428
|
// src/sac/proposal-lifecycle.ts
|
|
37392
37429
|
init_fs();
|
|
37393
37430
|
import { createHash as createHash30, randomUUID as randomUUID7 } from "crypto";
|
|
37394
|
-
import { appendFile as appendFile8, mkdir as mkdir35, readdir as
|
|
37431
|
+
import { appendFile as appendFile8, mkdir as mkdir35, readdir as readdir21, readFile as readFile64 } from "fs/promises";
|
|
37395
37432
|
import path121 from "path";
|
|
37396
37433
|
|
|
37397
37434
|
// src/sac/trusted-wrap-up.ts
|
|
@@ -37541,7 +37578,7 @@ function sessionDir(projectPath, sessionId, dataDir) {
|
|
|
37541
37578
|
// src/session/slate.ts
|
|
37542
37579
|
init_fs();
|
|
37543
37580
|
init_assembly();
|
|
37544
|
-
import { mkdir as mkdir33, readFile as readFile56, rm as rm7 } from "fs/promises";
|
|
37581
|
+
import { mkdir as mkdir33, readFile as readFile56, readdir as readdir19, rm as rm7, stat as stat16 } from "fs/promises";
|
|
37545
37582
|
import path113 from "path";
|
|
37546
37583
|
init_redact();
|
|
37547
37584
|
var SLATE_SEED_KINDS = [
|
|
@@ -37766,6 +37803,9 @@ function readJsonl2(file) {
|
|
|
37766
37803
|
...o.isError === true ? { isError: true } : {},
|
|
37767
37804
|
...typeof o.spillPath === "string" && o.spillPath.length > 0 ? { spillPath: o.spillPath } : {},
|
|
37768
37805
|
...o.collapsed === true ? { collapsed: true } : {},
|
|
37806
|
+
...typeof o.trailStep === "number" && Number.isInteger(o.trailStep) && o.trailStep > 0 ? { trailStep: o.trailStep } : {},
|
|
37807
|
+
...o.packed === true ? { packed: true } : {},
|
|
37808
|
+
...o.slateFrame === true ? { slateFrame: true } : {},
|
|
37769
37809
|
...typeof o.ts === "string" && o.ts.length > 0 ? { ts: o.ts } : {},
|
|
37770
37810
|
...reasoning !== undefined ? { reasoning } : {}
|
|
37771
37811
|
});
|
|
@@ -38136,7 +38176,7 @@ async function consumeConfirmToken(cwd, workspaceId, proposalId, idempotencyKey,
|
|
|
38136
38176
|
init_dedup();
|
|
38137
38177
|
init_store();
|
|
38138
38178
|
init_config();
|
|
38139
|
-
import { readFile as readFile59, readdir as
|
|
38179
|
+
import { readFile as readFile59, readdir as readdir20 } from "fs/promises";
|
|
38140
38180
|
import { randomUUID as randomUUID6 } from "crypto";
|
|
38141
38181
|
import path118 from "path";
|
|
38142
38182
|
|
|
@@ -38369,7 +38409,7 @@ async function collectWikiDecisionEntries(cwd) {
|
|
|
38369
38409
|
const dir = path118.join(cwd, ".metaproject", "wiki", "decisions");
|
|
38370
38410
|
let files;
|
|
38371
38411
|
try {
|
|
38372
|
-
files = (await
|
|
38412
|
+
files = (await readdir20(dir)).filter((name) => name.endsWith(".md"));
|
|
38373
38413
|
} catch {
|
|
38374
38414
|
return [];
|
|
38375
38415
|
}
|
|
@@ -38720,7 +38760,7 @@ init_json();
|
|
|
38720
38760
|
init_guard();
|
|
38721
38761
|
import { createHash as createHash29 } from "crypto";
|
|
38722
38762
|
import { homedir as homedir2 } from "os";
|
|
38723
|
-
import { readFile as readFile62, stat as
|
|
38763
|
+
import { readFile as readFile62, stat as stat17 } from "fs/promises";
|
|
38724
38764
|
import path120 from "path";
|
|
38725
38765
|
var VERSION = "0.1.0";
|
|
38726
38766
|
var PROJECT_SKILLS_DIR = ".metaproject/project-skills";
|
|
@@ -38897,7 +38937,7 @@ async function classifyTarget(absoluteTarget, targetExists) {
|
|
|
38897
38937
|
if (!targetExists) {
|
|
38898
38938
|
return "symbol-or-concept";
|
|
38899
38939
|
}
|
|
38900
|
-
const stats = await
|
|
38940
|
+
const stats = await stat17(absoluteTarget);
|
|
38901
38941
|
return stats.isDirectory() ? "directory" : "file";
|
|
38902
38942
|
}
|
|
38903
38943
|
async function existingRelativePaths(projectRoot, candidates) {
|
|
@@ -39420,7 +39460,7 @@ class ProposalLifecycleService {
|
|
|
39420
39460
|
const proposalsDir = path121.join(this.root, ".metaproject", "workspaces", workspaceId, "proposals");
|
|
39421
39461
|
let entries;
|
|
39422
39462
|
try {
|
|
39423
|
-
entries = (await
|
|
39463
|
+
entries = (await readdir21(proposalsDir)).filter((name) => name.endsWith(".json"));
|
|
39424
39464
|
} catch (error) {
|
|
39425
39465
|
if (isNotFound(error))
|
|
39426
39466
|
return [];
|
|
@@ -39930,7 +39970,7 @@ function normalizeCollaborationResult(value) {
|
|
|
39930
39970
|
}
|
|
39931
39971
|
// src/session/external-slate.ts
|
|
39932
39972
|
init_fs();
|
|
39933
|
-
import { mkdir as mkdir38, readdir as
|
|
39973
|
+
import { mkdir as mkdir38, readdir as readdir22, readFile as readFile66 } from "fs/promises";
|
|
39934
39974
|
import path124 from "path";
|
|
39935
39975
|
|
|
39936
39976
|
// src/sac/machine-wrap-up.ts
|
|
@@ -40398,7 +40438,7 @@ async function writeExternalSlate(cwd, externalSessionId, update) {
|
|
|
40398
40438
|
}
|
|
40399
40439
|
async function listExternalSlateIds(cwd) {
|
|
40400
40440
|
try {
|
|
40401
|
-
const entries = await
|
|
40441
|
+
const entries = await readdir22(externalSlatesDir(cwd));
|
|
40402
40442
|
return entries.filter((name) => name.endsWith(".json")).map((name) => name.slice(0, -".json".length));
|
|
40403
40443
|
} catch (error) {
|
|
40404
40444
|
if (isNotFound(error))
|
|
@@ -41133,6 +41173,18 @@ var HELP_GROUPS = [
|
|
|
41133
41173
|
group: "Working in keryx shell",
|
|
41134
41174
|
summary: "Compact model context \u2014 /compact [focus] (archive kept)."
|
|
41135
41175
|
},
|
|
41176
|
+
{
|
|
41177
|
+
kind: "slash",
|
|
41178
|
+
name: "/trail",
|
|
41179
|
+
group: "Working in keryx shell",
|
|
41180
|
+
summary: "The tool calls this session recorded (what stays when older rounds leave the request) \u2014 /trail [count] [tool=NAME] [file=TEXT] [from=STEP] [to=STEP]."
|
|
41181
|
+
},
|
|
41182
|
+
{
|
|
41183
|
+
kind: "slash",
|
|
41184
|
+
name: "/notes",
|
|
41185
|
+
group: "Working in keryx shell",
|
|
41186
|
+
summary: "The notes the model keeps for itself (the facts that survive older rounds) \u2014 /notes [key]."
|
|
41187
|
+
},
|
|
41136
41188
|
{
|
|
41137
41189
|
kind: "slash",
|
|
41138
41190
|
name: "/rewind",
|
|
@@ -41329,6 +41381,12 @@ var HELP_GROUPS = [
|
|
|
41329
41381
|
group: "Automation",
|
|
41330
41382
|
summary: "Pending remote approvals: list them, allow or deny one call, once (the local answer path of keryx serve)."
|
|
41331
41383
|
},
|
|
41384
|
+
{
|
|
41385
|
+
kind: "cli",
|
|
41386
|
+
name: "permissions",
|
|
41387
|
+
group: "Automation",
|
|
41388
|
+
summary: "The saved shell rules an Always answer leaves behind: list them (honoured or not, with the reason) and remove one."
|
|
41389
|
+
},
|
|
41332
41390
|
{
|
|
41333
41391
|
kind: "cli",
|
|
41334
41392
|
name: "governance",
|
|
@@ -41339,7 +41397,7 @@ var HELP_GROUPS = [
|
|
|
41339
41397
|
kind: "cli",
|
|
41340
41398
|
name: "decisions",
|
|
41341
41399
|
group: "Automation",
|
|
41342
|
-
summary:
|
|
41400
|
+
summary: `Recommendation journal: record each agent question with options and its recommendation, the human's choice, and report how often they agree (a third are asked blind). A question also takes your own text: the last row "\u0421\u0432\u043E\u0439 \u043E\u0442\u0432\u0435\u0442\u2026" in the shell, the "\u270D \u0421\u0432\u043E\u0439 \u043E\u0442\u0432\u0435\u0442" button in Telegram, and Tab after an option adds a typed reason.`
|
|
41343
41401
|
},
|
|
41344
41402
|
{
|
|
41345
41403
|
kind: "cli",
|
|
@@ -41383,6 +41441,12 @@ var HELP_GROUPS = [
|
|
|
41383
41441
|
group: "Automation",
|
|
41384
41442
|
summary: "Pending remote approvals with scope, consequence and expiry \u2014 allow or deny one call, once."
|
|
41385
41443
|
},
|
|
41444
|
+
{
|
|
41445
|
+
kind: "slash",
|
|
41446
|
+
name: "/permissions",
|
|
41447
|
+
group: "Automation",
|
|
41448
|
+
summary: "The saved shell rules (what Always remembered): honoured or not, session grants \u2014 remove one."
|
|
41449
|
+
},
|
|
41386
41450
|
{
|
|
41387
41451
|
kind: "slash",
|
|
41388
41452
|
name: "/external-diff",
|
|
@@ -41399,7 +41463,7 @@ var HELP_GROUPS = [
|
|
|
41399
41463
|
kind: "slash",
|
|
41400
41464
|
name: "/decisions",
|
|
41401
41465
|
group: "Automation",
|
|
41402
|
-
summary: "Recommendation journal report: match share by mode and stage,
|
|
41466
|
+
summary: "Recommendation journal report: match share by mode and stage, the deviations with their reasons, and your own answers and typed reasons in full (marked \u270D in the sidebar row)."
|
|
41403
41467
|
},
|
|
41404
41468
|
{
|
|
41405
41469
|
kind: "slash",
|
|
@@ -41417,7 +41481,13 @@ var HELP_GROUPS = [
|
|
|
41417
41481
|
kind: "slash",
|
|
41418
41482
|
name: "/remote-control",
|
|
41419
41483
|
group: "Automation",
|
|
41420
|
-
summary:
|
|
41484
|
+
summary: 'Drive this session from a Telegram topic: send lines, get replies, answer approvals and questions (an option button, or "\u270D \u0421\u0432\u043E\u0439 \u043E\u0442\u0432\u0435\u0442" and a reply with your own text). Off by default; [name|off|status].'
|
|
41485
|
+
},
|
|
41486
|
+
{
|
|
41487
|
+
kind: "slash",
|
|
41488
|
+
name: "/history",
|
|
41489
|
+
group: "Automation",
|
|
41490
|
+
summary: "Post the last messages of this session to the Telegram topic, oldest first. [N], 1 to 20; 10 by default."
|
|
41421
41491
|
},
|
|
41422
41492
|
{
|
|
41423
41493
|
kind: "slash",
|
|
@@ -41431,6 +41501,12 @@ var HELP_GROUPS = [
|
|
|
41431
41501
|
group: "Automation",
|
|
41432
41502
|
summary: "How Telegram replies are written: tables and lists as rich messages or HTML, with a fallback. [auto|rich|html|plain]."
|
|
41433
41503
|
},
|
|
41504
|
+
{
|
|
41505
|
+
kind: "slash",
|
|
41506
|
+
name: "/remote-policy",
|
|
41507
|
+
group: "Automation",
|
|
41508
|
+
summary: "Telegram defaults for a turn started there: mode ask|trust, run limit, approval wait. Never changes the shell's /mode."
|
|
41509
|
+
},
|
|
41434
41510
|
{
|
|
41435
41511
|
kind: "cli",
|
|
41436
41512
|
name: "acp",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mrciphersmith/keryx",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.73",
|
|
4
4
|
"description": "Version-controlled project context for AI coding agents: code graph, architecture wiki, project memory, relevant tests, quality signals, and task flows.",
|
|
5
5
|
"private": false,
|
|
6
6
|
"publishConfig": {
|
package/src/gdgraph/service.ts
CHANGED
|
@@ -25,6 +25,11 @@ export { buildAffectedReport, type AffectedReport, type AffectedReportOptions }
|
|
|
25
25
|
// `buildAffectedReport` above already follows).
|
|
26
26
|
export { checkGraphStaleness, type StalenessCheck, type StalenessStatus } from "./staleness";
|
|
27
27
|
|
|
28
|
+
// Flow 393: the shared token estimator, re-exported so session code that sizes the
|
|
29
|
+
// slate frame goes through this facade instead of a direct edge into
|
|
30
|
+
// `gdgraph/repomap.ts`.
|
|
31
|
+
export { estimateTokens } from "./repomap";
|
|
32
|
+
|
|
28
33
|
export interface GdgraphService {
|
|
29
34
|
build(cwd: string): Promise<{ nodes: number; edges: number; summaryPath: string }>;
|
|
30
35
|
loadGraph(cwd: string): Promise<GraphData>;
|
|
@@ -87,22 +87,20 @@ blockers?: string[] — unresolved critical unknowns
|
|
|
87
87
|
- **Max 8 questions** — stop when enough context is gathered
|
|
88
88
|
- **Confirm before proceeding** — summarize gathered context, state the summary's own confidence (the weakest of the answers it rests on), and ask if correct
|
|
89
89
|
|
|
90
|
-
##
|
|
90
|
+
## Host or no host
|
|
91
|
+
|
|
92
|
+
Before the first question, check whether a host can show it: the `ask_user` tool is available in this run.
|
|
91
93
|
|
|
92
|
-
|
|
93
|
-
-
|
|
94
|
-
-
|
|
95
|
-
-
|
|
96
|
-
- What should NOT be changed (constraints)?
|
|
94
|
+
- **Host present:** ask every question through `ask_user`, one per call, with the A/B/C/D options as its options.
|
|
95
|
+
- **No host:** ask NO question, not even in plain text; nobody is there to answer it. Return `status: "NEEDS_CONTEXT"` with the `assumptions` you would have asked about (question, assumption, `confidence: "assumption"`), `ready_to_proceed: false`. The caller decides.
|
|
96
|
+
- A cancelled or empty `ask_user` answer is not an answer: record it as an assumption and stop asking.
|
|
97
|
+
- Each `ask_user` question is recorded in the recommendation journal by the tool itself (source, arm, recommendation, answer); you do not record it. `src/decisions/interviewer-path.test.ts` pins this path through the agent's real tool roster.
|
|
97
98
|
|
|
98
|
-
|
|
99
|
-
- What specific concerns should the review focus on?
|
|
100
|
-
- What is the acceptance criteria?
|
|
99
|
+
## Question Bank by Goal Type
|
|
101
100
|
|
|
102
|
-
|
|
103
|
-
-
|
|
104
|
-
-
|
|
105
|
-
- Who else is affected by this decision?
|
|
101
|
+
- **Implementation:** expected input/output, edge cases that must be handled, performance or scale requirement, what must NOT change.
|
|
102
|
+
- **Review:** which concerns the review should focus on, the acceptance criteria.
|
|
103
|
+
- **Architecture/design:** hard constraints (performance, compat, timeline), what worries you most, who else is affected.
|
|
106
104
|
|
|
107
105
|
## Red Flags
|
|
108
106
|
|