From 0cd08e78d386a68da8b08f6e9f40755bf3cf6a5b Mon Sep 17 00:00:00 2001 From: Chris Hendrickson Date: Sun, 3 May 2026 13:52:08 -0400 Subject: [PATCH] fix(cli,vault): polish init output and interactive set --- .gitignore | 8 +++----- .project/.gitignore | 3 +++ packages/cli/bin/dew.dart | 9 ++++++++- packages/core/lib/src/init.dart | 14 ++++++++++++++ packages/vault/lib/src/command_output.dart | 17 ++++++++++++++++- .../vault/lib/src/commands/set_command.dart | 3 ++- 6 files changed, 46 insertions(+), 8 deletions(-) create mode 100644 .project/.gitignore diff --git a/.gitignore b/.gitignore index f80ea9b..6e78fd1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,4 @@ -# https://dart.dev/guides/libraries/private-files -# Created by `dart pub` -.dart_tool/ +# Dew Git Ignore -# Compiled toolchain binaries -.project/toolchain/ +## Dart +.dart_tool/ diff --git a/.project/.gitignore b/.project/.gitignore new file mode 100644 index 0000000..7b1ac90 --- /dev/null +++ b/.project/.gitignore @@ -0,0 +1,3 @@ +/cache/ +/secrets/ +/toolchain/ diff --git a/packages/cli/bin/dew.dart b/packages/cli/bin/dew.dart index e4d1f40..b033a90 100644 --- a/packages/cli/bin/dew.dart +++ b/packages/cli/bin/dew.dart @@ -1,3 +1,5 @@ +import 'dart:io'; + import 'package:args/command_runner.dart'; import 'package:dew_core/dew_core.dart'; import 'package:dew_kanban/dew_kanban.dart' as kanban; @@ -18,5 +20,10 @@ Future main(List args) async { runner.addCommand(command); } - await runner.run(args); + try { + await runner.run(args); + } on UsageException catch (error) { + stderr.writeln(error); + exitCode = 64; + } } diff --git a/packages/core/lib/src/init.dart b/packages/core/lib/src/init.dart index 014d53b..d360254 100644 --- a/packages/core/lib/src/init.dart +++ b/packages/core/lib/src/init.dart @@ -60,6 +60,12 @@ dew: color: "green" '''; +const _projectGitignore = ''' +/secrets/ +/toolchain/ +/cache/ +'''; + class InitCommand extends Command { final List _hooks; final FileSystem _fs; @@ -97,6 +103,7 @@ class InitCommand extends Command { final projectDir = _fs.directory(p.join(projectRoot, '.project')); final configFile = _fs.file(p.join(projectDir.path, 'dew.yaml')); + final gitignoreFile = _fs.file(p.join(projectDir.path, '.gitignore')); await projectDir.create(recursive: true); @@ -107,6 +114,13 @@ class InitCommand extends Command { print(' created .project/dew.yaml'); } + if (await gitignoreFile.exists()) { + print(' found .project/.gitignore (already exists, skipping)'); + } else { + await gitignoreFile.writeAsString(_projectGitignore); + print(' created .project/.gitignore'); + } + final config = DewConfig.fromYaml( loadYaml(await configFile.readAsString()) as YamlMap, ); diff --git a/packages/vault/lib/src/command_output.dart b/packages/vault/lib/src/command_output.dart index 918fc5d..144ee6d 100644 --- a/packages/vault/lib/src/command_output.dart +++ b/packages/vault/lib/src/command_output.dart @@ -42,6 +42,7 @@ Future readSecretInput( required FileSystem fs, bool required = true, bool allowStdin = true, + String? prompt, String? projectRoot, }) async { final envVar = args['env']?.toString(); @@ -67,11 +68,25 @@ Future readSecretInput( return value.trimRight(); } - if (!allowStdin || stdin.hasTerminal) { + if (!allowStdin) { if (!required) return null; throw ArgumentError('Missing secret value. Use --env, --file, or pipe input.'); } + if (stdin.hasTerminal) { + if (prompt != null) { + stdout.write('$prompt: '); + } + final input = stdin.readLineSync(); + if (input == null || input.trim().isEmpty) { + if (!required) return null; + throw ArgumentError( + 'Missing secret value. Use --env, --file, or pipe input.', + ); + } + return input.trimRight(); + } + final input = (await stdin.transform(utf8.decoder).join()).trimRight(); if (input.trim().isEmpty) { if (!required) return null; diff --git a/packages/vault/lib/src/commands/set_command.dart b/packages/vault/lib/src/commands/set_command.dart index e9ece6c..924ebcc 100644 --- a/packages/vault/lib/src/commands/set_command.dart +++ b/packages/vault/lib/src/commands/set_command.dart @@ -61,7 +61,8 @@ class SetCommand extends DewCommand with DewToolCommand { fs: context.fs, projectRoot: context.root, required: true, - allowStdin: false, + allowStdin: true, + prompt: 'Enter value for secret "$secretName"', ); await store.write(secretName, value!, metadata: metadata);