javi-forge 1.32.0 → 1.34.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.
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Pure refusal → remediation table for the CLI layer (Linux hardening, Slice A).
3
+ *
4
+ * The secure-fs adapters stay PROVERS: they emit stable `SecureRefusal` codes
5
+ * plus a stable detail token and carry ZERO user copy. This module is the only
6
+ * place that turns one of those tokens into an actionable next step, so the
7
+ * proof algorithms and their refusal identities never move when the copy does.
8
+ *
9
+ * The table is deliberately narrow. A remediation is emitted ONLY when the user
10
+ * can actually fix the cause: an unresolvable `getfacl` is fixed by installing
11
+ * the `acl` package, while a REAL extended ACL (the adapter ran and found a
12
+ * named-user entry) is not — suggesting a package install there would be
13
+ * actively misleading. No I/O, no rendering, no Ink.
14
+ */
15
+ import type { SecureRefusal } from "./secure-fs-transaction.js";
16
+ /** The one actionable line for a host whose POSIX ACL adapter is missing. */
17
+ export declare const ACL_PACKAGE_REMEDIATION = "install the acl package (provides getfacl): apt install acl \u00B7 apk add acl \u00B7 dnf install acl";
18
+ /**
19
+ * The actionable line for a refusal + detail pair, or `undefined` when nothing
20
+ * the user can do would change the outcome.
21
+ */
22
+ export declare function remediationForRefusal(refusal: SecureRefusal, detail?: string): string | undefined;
23
+ /**
24
+ * The same lookup for an already-rendered refusal MESSAGE (the transaction
25
+ * flattens `refusal`/`detail` into strings such as `acl /path: getfacl absent`).
26
+ * Matching is anchored to the message TAIL so prose that merely mentions the
27
+ * token never triggers a wrong hint.
28
+ */
29
+ export declare function remediationForMessage(message: string): string | undefined;
30
+ //# sourceMappingURL=secure-refusal-remediation.d.ts.map
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Pure refusal → remediation table for the CLI layer (Linux hardening, Slice A).
3
+ *
4
+ * The secure-fs adapters stay PROVERS: they emit stable `SecureRefusal` codes
5
+ * plus a stable detail token and carry ZERO user copy. This module is the only
6
+ * place that turns one of those tokens into an actionable next step, so the
7
+ * proof algorithms and their refusal identities never move when the copy does.
8
+ *
9
+ * The table is deliberately narrow. A remediation is emitted ONLY when the user
10
+ * can actually fix the cause: an unresolvable `getfacl` is fixed by installing
11
+ * the `acl` package, while a REAL extended ACL (the adapter ran and found a
12
+ * named-user entry) is not — suggesting a package install there would be
13
+ * actively misleading. No I/O, no rendering, no Ink.
14
+ */
15
+ import { ACL_DETAIL } from "./secure-fs-posix.js";
16
+ /** The one actionable line for a host whose POSIX ACL adapter is missing. */
17
+ export const ACL_PACKAGE_REMEDIATION = "install the acl package (provides getfacl): apt install acl · apk add acl · dnf install acl";
18
+ /** Detail tokens that map to a remediation, keyed by refusal code. */
19
+ const REMEDIATION_TABLE = {
20
+ "unsupported-posix-acl": {
21
+ [ACL_DETAIL.getfaclAbsent]: ACL_PACKAGE_REMEDIATION,
22
+ },
23
+ };
24
+ /**
25
+ * The actionable line for a refusal + detail pair, or `undefined` when nothing
26
+ * the user can do would change the outcome.
27
+ */
28
+ export function remediationForRefusal(refusal, detail) {
29
+ if (detail === undefined)
30
+ return undefined;
31
+ return REMEDIATION_TABLE[refusal]?.[detail];
32
+ }
33
+ /**
34
+ * The same lookup for an already-rendered refusal MESSAGE (the transaction
35
+ * flattens `refusal`/`detail` into strings such as `acl /path: getfacl absent`).
36
+ * Matching is anchored to the message TAIL so prose that merely mentions the
37
+ * token never triggers a wrong hint.
38
+ */
39
+ export function remediationForMessage(message) {
40
+ for (const details of Object.values(REMEDIATION_TABLE)) {
41
+ for (const [detail, line] of Object.entries(details)) {
42
+ if (message.endsWith(detail))
43
+ return line;
44
+ }
45
+ }
46
+ return undefined;
47
+ }
48
+ //# sourceMappingURL=secure-refusal-remediation.js.map
package/dist/ui/App.js CHANGED
@@ -2,6 +2,7 @@ import path from "node:path";
2
2
  import { Box } from "ink";
3
3
  import React, { useState } from "react";
4
4
  import { initProject } from "../commands/init.js";
5
+ import { buildInitOptions } from "./build-init-options.js";
5
6
  import CISelector from "./CISelector.js";
6
7
  import Header from "./Header.js";
7
8
  import HookProfileSelector from "./HookProfileSelector.js";
@@ -80,29 +81,15 @@ export default function App({ dryRun = false, presetStack, presetCI, presetMemor
80
81
  };
81
82
  const runInit = async (opts) => {
82
83
  setStage("running");
83
- await initProject({
84
+ await initProject(buildInitOptions(opts, {
84
85
  projectName,
85
86
  projectDir,
86
87
  stack,
87
88
  ciProvider,
88
89
  memory,
89
- aiSync: opts.aiSync,
90
- sdd: opts.sdd,
91
- ghagga: opts.ghagga,
92
- contextDir: opts.contextDir,
93
- claudeMd: opts.claudeMd,
94
- securityHooks: opts.securityHooks,
95
- hookProfile: opts.hookProfile,
96
- // Derived from securityHooks alone — ALL profiles incl. Minimal
97
- // install the managed guard when security hooks are enabled.
98
- claudePreToolUseGuard: opts.securityHooks,
99
- codeGraph: opts.codeGraph,
100
- localAi: opts.localAi,
101
- dockerDeploy: false,
102
- dockerServiceName: "app",
103
90
  mock: presetMock,
104
91
  dryRun,
105
- }, (step) => setSteps((prev) => {
92
+ }), (step) => setSteps((prev) => {
106
93
  const idx = prev.findIndex((s) => s.id === step.id);
107
94
  if (idx >= 0) {
108
95
  const next = [...prev];
@@ -0,0 +1,44 @@
1
+ import type { CIProvider, HookProfile, InitOptions, MemoryOption, Stack } from "../types/index.js";
2
+ /**
3
+ * Wizard-collected toggles for an init run — the subset the user answers
4
+ * interactively (or via presets). Mirrors the `runInit` opts parameter.
5
+ */
6
+ export interface InitOptionsWizardResult {
7
+ aiSync: boolean;
8
+ sdd: boolean;
9
+ contextDir: boolean;
10
+ claudeMd: boolean;
11
+ ghagga: boolean;
12
+ securityHooks: boolean;
13
+ codeGraph: boolean;
14
+ localAi: boolean;
15
+ hookProfile: HookProfile;
16
+ }
17
+ /**
18
+ * Surrounding context resolved before the wizard finishes — project identity,
19
+ * stack/CI/memory choices, and run flags (mock/dryRun).
20
+ */
21
+ export interface InitOptionsContext {
22
+ projectName: string;
23
+ projectDir: string;
24
+ stack: Stack;
25
+ ciProvider: CIProvider;
26
+ memory: MemoryOption;
27
+ mock: boolean;
28
+ dryRun: boolean;
29
+ }
30
+ /**
31
+ * Pure mapping from wizard result + surrounding context to the full
32
+ * {@link InitOptions} contract passed to `initProject`.
33
+ *
34
+ * Extracted from the single inline object literal in `App.tsx#runInit` so the
35
+ * derivation is unit-testable. Behavior-identical: field values must match the
36
+ * previous inline literal exactly.
37
+ *
38
+ * Notably, `claudePreToolUseGuard` is derived from `securityHooks` alone — ALL
39
+ * hook profiles (including "minimal") install the managed guard when security
40
+ * hooks are enabled. A regression here silently disables managed-guard
41
+ * installation, so it is pinned by build-init-options.test.ts.
42
+ */
43
+ export declare function buildInitOptions(opts: InitOptionsWizardResult, ctx: InitOptionsContext): InitOptions;
44
+ //# sourceMappingURL=build-init-options.d.ts.map
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Pure mapping from wizard result + surrounding context to the full
3
+ * {@link InitOptions} contract passed to `initProject`.
4
+ *
5
+ * Extracted from the single inline object literal in `App.tsx#runInit` so the
6
+ * derivation is unit-testable. Behavior-identical: field values must match the
7
+ * previous inline literal exactly.
8
+ *
9
+ * Notably, `claudePreToolUseGuard` is derived from `securityHooks` alone — ALL
10
+ * hook profiles (including "minimal") install the managed guard when security
11
+ * hooks are enabled. A regression here silently disables managed-guard
12
+ * installation, so it is pinned by build-init-options.test.ts.
13
+ */
14
+ export function buildInitOptions(opts, ctx) {
15
+ return {
16
+ projectName: ctx.projectName,
17
+ projectDir: ctx.projectDir,
18
+ stack: ctx.stack,
19
+ ciProvider: ctx.ciProvider,
20
+ memory: ctx.memory,
21
+ aiSync: opts.aiSync,
22
+ sdd: opts.sdd,
23
+ ghagga: opts.ghagga,
24
+ contextDir: opts.contextDir,
25
+ claudeMd: opts.claudeMd,
26
+ securityHooks: opts.securityHooks,
27
+ hookProfile: opts.hookProfile,
28
+ // Derived from securityHooks alone — ALL profiles incl. Minimal
29
+ // install the managed guard when security hooks are enabled.
30
+ claudePreToolUseGuard: opts.securityHooks,
31
+ codeGraph: opts.codeGraph,
32
+ localAi: opts.localAi,
33
+ dockerDeploy: false,
34
+ dockerServiceName: "app",
35
+ mock: ctx.mock,
36
+ dryRun: ctx.dryRun,
37
+ };
38
+ }
39
+ //# sourceMappingURL=build-init-options.js.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "javi-forge",
3
- "version": "1.32.0",
3
+ "version": "1.34.0",
4
4
  "description": "Project scaffolding and AI-ready CI bootstrap",
5
5
  "type": "module",
6
6
  "bin": {