@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/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": 131,
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 readdir20, readFile as readFile64 } from "fs/promises";
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 readdir19 } from "fs/promises";
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 readdir19(dir)).filter((name) => name.endsWith(".md"));
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 stat16 } from "fs/promises";
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 stat16(absoluteTarget);
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 readdir20(proposalsDir)).filter((name) => name.endsWith(".json"));
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 readdir21, readFile as readFile66 } from "fs/promises";
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 readdir21(externalSlatesDir(cwd));
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: "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)."
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, and the deviations with their reasons."
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: "Drive this session from a Telegram topic: send lines, get replies, answer approvals. Off by default; [name|off|status]."
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.67",
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": {
@@ -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
- ## Question Bank by Goal Type
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
- ### For implementation goals
93
- - What is the expected input/output?
94
- - What are the edge cases that must be handled?
95
- - What is the performance/scale requirement?
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
- ### For review goals
99
- - What specific concerns should the review focus on?
100
- - What is the acceptance criteria?
99
+ ## Question Bank by Goal Type
101
100
 
102
- ### For architecture/design goals
103
- - What are the hard constraints (performance, compat, timeline)?
104
- - What are you most worried about?
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