nomoreide 0.1.76 → 0.1.77

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,61 @@
1
+ import { z } from "zod";
2
+ export interface AppSettings {
3
+ version: 1;
4
+ terminal: {
5
+ fontSize: number;
6
+ cursorStyle: "block" | "underline" | "bar";
7
+ scrollback: number;
8
+ copyOnSelect: boolean;
9
+ confirmTerminate: boolean;
10
+ };
11
+ }
12
+ export declare const DEFAULT_APP_SETTINGS: AppSettings;
13
+ export declare const appSettingsPatchSchema: z.ZodObject<{
14
+ terminal: z.ZodOptional<z.ZodObject<{
15
+ fontSize: z.ZodOptional<z.ZodNumber>;
16
+ cursorStyle: z.ZodOptional<z.ZodEnum<["block", "underline", "bar"]>>;
17
+ scrollback: z.ZodOptional<z.ZodNumber>;
18
+ copyOnSelect: z.ZodOptional<z.ZodBoolean>;
19
+ confirmTerminate: z.ZodOptional<z.ZodBoolean>;
20
+ }, "strict", z.ZodTypeAny, {
21
+ fontSize?: number | undefined;
22
+ cursorStyle?: "block" | "underline" | "bar" | undefined;
23
+ scrollback?: number | undefined;
24
+ copyOnSelect?: boolean | undefined;
25
+ confirmTerminate?: boolean | undefined;
26
+ }, {
27
+ fontSize?: number | undefined;
28
+ cursorStyle?: "block" | "underline" | "bar" | undefined;
29
+ scrollback?: number | undefined;
30
+ copyOnSelect?: boolean | undefined;
31
+ confirmTerminate?: boolean | undefined;
32
+ }>>;
33
+ }, "strict", z.ZodTypeAny, {
34
+ terminal?: {
35
+ fontSize?: number | undefined;
36
+ cursorStyle?: "block" | "underline" | "bar" | undefined;
37
+ scrollback?: number | undefined;
38
+ copyOnSelect?: boolean | undefined;
39
+ confirmTerminate?: boolean | undefined;
40
+ } | undefined;
41
+ }, {
42
+ terminal?: {
43
+ fontSize?: number | undefined;
44
+ cursorStyle?: "block" | "underline" | "bar" | undefined;
45
+ scrollback?: number | undefined;
46
+ copyOnSelect?: boolean | undefined;
47
+ confirmTerminate?: boolean | undefined;
48
+ } | undefined;
49
+ }>;
50
+ export type AppSettingsPatch = z.infer<typeof appSettingsPatchSchema>;
51
+ export declare function defaultAppSettingsPath(): string;
52
+ export declare class AppSettingsStore {
53
+ private readonly settingsPath;
54
+ private mutationQueue;
55
+ constructor(settingsPath?: string);
56
+ load(): Promise<AppSettings>;
57
+ update(patch: AppSettingsPatch): Promise<AppSettings>;
58
+ reset(): Promise<AppSettings>;
59
+ private enqueueMutation;
60
+ private persist;
61
+ }
@@ -0,0 +1,106 @@
1
+ import { randomUUID } from "node:crypto";
2
+ import { mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
3
+ import { homedir } from "node:os";
4
+ import { basename, dirname, join } from "node:path";
5
+ import { z } from "zod";
6
+ export const DEFAULT_APP_SETTINGS = Object.freeze({
7
+ version: 1,
8
+ terminal: Object.freeze({
9
+ fontSize: 13,
10
+ cursorStyle: "block",
11
+ scrollback: 5_000,
12
+ copyOnSelect: false,
13
+ confirmTerminate: true,
14
+ }),
15
+ });
16
+ const terminalSettingsShape = {
17
+ fontSize: z.number().int().min(10).max(24),
18
+ cursorStyle: z.enum(["block", "underline", "bar"]),
19
+ scrollback: z.number().int().min(500).max(100_000),
20
+ copyOnSelect: z.boolean(),
21
+ confirmTerminate: z.boolean(),
22
+ };
23
+ const appSettingsSchema = z.object({
24
+ version: z.literal(1),
25
+ terminal: z.object(terminalSettingsShape),
26
+ });
27
+ export const appSettingsPatchSchema = z
28
+ .object({
29
+ terminal: z.object(terminalSettingsShape).partial().strict().optional(),
30
+ })
31
+ .strict();
32
+ export function defaultAppSettingsPath() {
33
+ const configuredRoot = process.env.XDG_CONFIG_HOME?.trim();
34
+ const configRoot = configuredRoot || join(homedir(), ".config");
35
+ return join(configRoot, "nomoreide", "settings.json");
36
+ }
37
+ export class AppSettingsStore {
38
+ settingsPath;
39
+ mutationQueue = Promise.resolve();
40
+ constructor(settingsPath = defaultAppSettingsPath()) {
41
+ this.settingsPath = settingsPath;
42
+ }
43
+ async load() {
44
+ try {
45
+ const contents = await readFile(this.settingsPath, "utf8");
46
+ return cloneSettings(appSettingsSchema.parse(JSON.parse(contents)));
47
+ }
48
+ catch (error) {
49
+ if (isMissingFileError(error)) {
50
+ return cloneSettings(DEFAULT_APP_SETTINGS);
51
+ }
52
+ throw error;
53
+ }
54
+ }
55
+ async update(patch) {
56
+ return this.enqueueMutation(async () => {
57
+ const current = await this.load();
58
+ const next = appSettingsSchema.parse({
59
+ ...current,
60
+ ...patch,
61
+ terminal: {
62
+ ...current.terminal,
63
+ ...patch.terminal,
64
+ },
65
+ });
66
+ await this.persist(next);
67
+ return cloneSettings(next);
68
+ });
69
+ }
70
+ async reset() {
71
+ return this.enqueueMutation(async () => {
72
+ const defaults = cloneSettings(DEFAULT_APP_SETTINGS);
73
+ await this.persist(defaults);
74
+ return cloneSettings(defaults);
75
+ });
76
+ }
77
+ enqueueMutation(operation) {
78
+ const result = this.mutationQueue.then(operation);
79
+ this.mutationQueue = result.then(() => undefined, () => undefined);
80
+ return result;
81
+ }
82
+ async persist(settings) {
83
+ const validated = appSettingsSchema.parse(settings);
84
+ const parentDirectory = dirname(this.settingsPath);
85
+ const temporaryPath = join(parentDirectory, `.${basename(this.settingsPath)}.${process.pid}.${randomUUID()}.tmp`);
86
+ await mkdir(parentDirectory, { recursive: true });
87
+ try {
88
+ await writeFile(temporaryPath, `${JSON.stringify(validated, null, 2)}\n`, { flag: "wx" });
89
+ await rename(temporaryPath, this.settingsPath);
90
+ }
91
+ catch (error) {
92
+ await unlink(temporaryPath).catch(() => undefined);
93
+ throw error;
94
+ }
95
+ }
96
+ }
97
+ function cloneSettings(settings) {
98
+ return structuredClone(settings);
99
+ }
100
+ function isMissingFileError(error) {
101
+ return (typeof error === "object" &&
102
+ error !== null &&
103
+ "code" in error &&
104
+ error.code === "ENOENT");
105
+ }
106
+ //# sourceMappingURL=app-settings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"app-settings.js","sourceRoot":"","sources":["../../src/core/app-settings.ts"],"names":[],"mappings":"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"}
@@ -1,12 +1,65 @@
1
- import type { BundleDefinition, DatabaseConnection, LogSourceDefinition, NoMoreIdeConfig, GitRepositoryDefinition, ServiceDefinition } from "./types.js";
1
+ import { z } from "zod";
2
+ import type { BundleDefinition, DatabaseConnection, LogSourceDefinition, NoMoreIdeConfig, ProjectPreferences, GitRepositoryDefinition, ServiceDefinition } from "./types.js";
2
3
  import { type Workflow } from "./workflows.js";
3
4
  import { type WorkflowTrigger } from "./workflow-triggers.js";
5
+ export declare const projectPreferencesSchema: z.ZodType<ProjectPreferences>;
6
+ export declare const projectPreferencesPatchSchema: z.ZodObject<{
7
+ logs: z.ZodOptional<z.ZodObject<{
8
+ showTimestamps: z.ZodOptional<z.ZodBoolean>;
9
+ wrapLines: z.ZodOptional<z.ZodBoolean>;
10
+ }, "strict", z.ZodTypeAny, {
11
+ showTimestamps?: boolean | undefined;
12
+ wrapLines?: boolean | undefined;
13
+ }, {
14
+ showTimestamps?: boolean | undefined;
15
+ wrapLines?: boolean | undefined;
16
+ }>>;
17
+ database: z.ZodOptional<z.ZodObject<{
18
+ confirmWrites: z.ZodOptional<z.ZodBoolean>;
19
+ resultLimit: z.ZodOptional<z.ZodNumber>;
20
+ }, "strict", z.ZodTypeAny, {
21
+ confirmWrites?: boolean | undefined;
22
+ resultLimit?: number | undefined;
23
+ }, {
24
+ confirmWrites?: boolean | undefined;
25
+ resultLimit?: number | undefined;
26
+ }>>;
27
+ }, "strict", z.ZodTypeAny, {
28
+ logs?: {
29
+ showTimestamps?: boolean | undefined;
30
+ wrapLines?: boolean | undefined;
31
+ } | undefined;
32
+ database?: {
33
+ confirmWrites?: boolean | undefined;
34
+ resultLimit?: number | undefined;
35
+ } | undefined;
36
+ }, {
37
+ logs?: {
38
+ showTimestamps?: boolean | undefined;
39
+ wrapLines?: boolean | undefined;
40
+ } | undefined;
41
+ database?: {
42
+ confirmWrites?: boolean | undefined;
43
+ resultLimit?: number | undefined;
44
+ } | undefined;
45
+ }>;
46
+ export type ProjectPreferencesPatch = z.infer<typeof projectPreferencesPatchSchema>;
47
+ export declare const DEFAULT_PROJECT_PREFERENCES: ProjectPreferences;
4
48
  export declare function defaultGlobalConfigPath(): string;
5
49
  export declare class ConfigStore {
6
50
  private readonly configPath;
51
+ private mutationQueue;
7
52
  constructor(configPath?: string);
8
53
  load(): Promise<NoMoreIdeConfig>;
54
+ private loadUnlocked;
9
55
  save(config: NoMoreIdeConfig): Promise<void>;
56
+ private persistUnlocked;
57
+ getPreferences(): Promise<ProjectPreferences>;
58
+ updatePreferences(patch: ProjectPreferencesPatch): Promise<ProjectPreferences>;
59
+ resetPreferences(): Promise<ProjectPreferences>;
60
+ private withConfigLock;
61
+ private enqueueMutation;
62
+ private mutateConfig;
10
63
  registerService(service: ServiceDefinition): Promise<NoMoreIdeConfig>;
11
64
  removeService(name: string): Promise<NoMoreIdeConfig>;
12
65
  registerBundle(bundle: BundleDefinition, previousName?: string): Promise<NoMoreIdeConfig>;
@@ -41,3 +94,5 @@ export declare class ConfigStore {
41
94
  export declare class ConfigValidationError extends Error {
42
95
  }
43
96
  export declare function isGitWorktree(path: string): Promise<boolean>;
97
+ /** @internal Deterministic stale-lock ownership seam used by regression tests. */
98
+ export declare function __recoverStaleConfigLockForTests(lockPath: string, afterOwnerRead: () => void | Promise<void>): Promise<void>;