fuzzy_notes 0.0.6 → 0.0.7
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.
- data/bin/fnote +14 -10
- data/lib/fuzzy_notes/cipher.rb +3 -10
- data/lib/fuzzy_notes/evernote_sync.rb +126 -22
- data/lib/fuzzy_notes/logger.rb +15 -5
- data/lib/fuzzy_notes/notes.rb +51 -14
- data/lib/fuzzy_notes/password_protected.rb +10 -0
- data/lib/fuzzy_notes.rb +4 -1
- metadata +41 -10
data/bin/fnote
CHANGED
@@ -16,12 +16,14 @@ optparse = OptionParser.new do |opts|
|
|
16
16
|
|
17
17
|
opts.on("-c", "--config [CONFIG]", "Specify config file") { |opt| options[:config] = opt}
|
18
18
|
opts.on("-p", "--print", "Dump matching notes to stdout") { |opt| options[:print] = true }
|
19
|
-
opts.on("-l", "--list", "List
|
20
|
-
opts.on("-i", "--info", "
|
19
|
+
opts.on("-l", "--list", "List matching notes") { |opt| options[:list] = true }
|
20
|
+
opts.on("-i", "--info", "Show statistics for matching notes") { |opt| options[:info] = true }
|
21
21
|
opts.on("-s", "--search", "Perform a full text search when matching notes") { |opt| options[:search] = true }
|
22
22
|
opts.on("-v", "--verbose", "Enable debug output") { |opt| options[:verbose] = true }
|
23
23
|
opts.on("-e", "--encrypt", "Encrypt matching notes") { |opt| options[:encrypt] = true }
|
24
24
|
opts.on("-d", "--decrypt", "Decrypt matching notes") { |opt| options[:decrypt] = true }
|
25
|
+
opts.on("-n", "--no-color", "Turn off ANSI color") { |opt| options[:color] = false}
|
26
|
+
opts.on("-u", "--evernote-update", "Synchronize evernote directory") { |opt| options[:evernote_update] = true }
|
25
27
|
opts.on("-h", "--help", "Show this message") {
|
26
28
|
puts opts
|
27
29
|
exit
|
@@ -47,23 +49,25 @@ end
|
|
47
49
|
# fetch config
|
48
50
|
#
|
49
51
|
config_path = \
|
50
|
-
|
52
|
+
File.exists?(options[:config].to_s) && options[:config] ||
|
51
53
|
File.exists?(CONFIG_PATH) && CONFIG_PATH
|
52
54
|
|
53
55
|
config = config_path ? YAML::load_file(config_path) : {}
|
54
|
-
|
56
|
+
log.info("config file not found, using defaults") if config.empty?
|
55
57
|
|
56
|
-
# find matching notes
|
57
|
-
#
|
58
58
|
notes = FuzzyNotes::Notes.new(:editor => config[:editor],
|
59
59
|
:note_paths => config[:note_paths],
|
60
|
+
:evernote_params => config[:evernote],
|
60
61
|
:full_text_search => options[:search] || config[:full_text_search],
|
61
|
-
:log_level => (options[:verbose] || config[:verbose]) ?
|
62
|
+
:log_level => (options[:verbose] || config[:verbose]) ? :debug : :info,
|
63
|
+
:color => (options[:color] == false || config[:color] == false) ? false : true,
|
62
64
|
:keywords => ARGV)
|
63
65
|
|
64
|
-
|
65
|
-
|
66
|
-
if options[:list]
|
66
|
+
notes.evernote_sync if options[:evernote_update]
|
67
|
+
|
68
|
+
if options[:list]
|
69
|
+
notes.list
|
70
|
+
elsif options[:info]
|
67
71
|
notes.info
|
68
72
|
elsif options[:print]
|
69
73
|
notes.cat
|
data/lib/fuzzy_notes/cipher.rb
CHANGED
@@ -2,6 +2,7 @@ require 'gibberish'
|
|
2
2
|
|
3
3
|
class FuzzyNotes::Cipher
|
4
4
|
include FuzzyNotes::Logger
|
5
|
+
include FuzzyNotes::PasswordProtected
|
5
6
|
|
6
7
|
PLAINTEXT_EXT = 'txt'
|
7
8
|
CIPHERTEXT_EXT = 'enc'
|
@@ -43,10 +44,10 @@ private
|
|
43
44
|
dirname = File.dirname(path)
|
44
45
|
filename = File.basename(path, '.*')
|
45
46
|
|
46
|
-
log.
|
47
|
+
log.info "#{Colors::CREATE} writing #{decrypt? ? 'un' : ''}encrypted file: #{Colors::PATH} #{dirname}/#{filename}.#{extension}"
|
47
48
|
File.open("#{dirname}/#{filename}.#{extension}", 'w') { |f| f << contents }
|
48
49
|
|
49
|
-
log.
|
50
|
+
log.info "#{Colors::DELETE} deleting #{decrypt? ? '' : 'un'}encrypted file: #{Colors::PATH} #{path}"
|
50
51
|
File.delete(path)
|
51
52
|
end
|
52
53
|
|
@@ -58,12 +59,4 @@ private
|
|
58
59
|
@action == :dec
|
59
60
|
end
|
60
61
|
|
61
|
-
def get_password
|
62
|
-
printf 'Enter password (will not be shown):'
|
63
|
-
`stty -echo`; password = STDIN.gets.strip;`stty echo`; puts "\n\n"
|
64
|
-
log.debug "entered password: #{password.inspect}"
|
65
|
-
password
|
66
|
-
end
|
67
|
-
|
68
|
-
|
69
62
|
end
|
@@ -1,23 +1,127 @@
|
|
1
1
|
require 'evernote'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
2
|
+
require 'fileutils'
|
3
|
+
require 'sanitize'
|
4
|
+
require 'digest/md5'
|
5
|
+
|
6
|
+
class FuzzyNotes::EvernoteSync
|
7
|
+
include FuzzyNotes::Logger
|
8
|
+
include FuzzyNotes::PasswordProtected
|
9
|
+
|
10
|
+
USER_STORE_URL = 'https://evernote.com/edam/user'
|
11
|
+
NOTE_STORE_URL = 'http://evernote.com/edam/note'
|
12
|
+
NOTE_EXT = 'html'
|
13
|
+
MAX_NOTES = 1000
|
14
|
+
|
15
|
+
# opts should be a hash with the following keys:
|
16
|
+
# :username, :password, :consumer_key, :consumer_secret
|
17
|
+
#
|
18
|
+
def initialize(params = {})
|
19
|
+
params.merge!(:password => get_password)
|
20
|
+
user_store = Evernote::UserStore.new(USER_STORE_URL, params)
|
21
|
+
begin
|
22
|
+
auth_result = user_store.authenticate
|
23
|
+
rescue Evernote::UserStore::AuthenticationFailure
|
24
|
+
log.error "Evernote authentication failed for #{Colors::USER} #{params[:username]}"
|
25
|
+
return
|
26
|
+
end
|
27
|
+
|
28
|
+
@path = params[:note_path]
|
29
|
+
user = auth_result.user
|
30
|
+
@token = auth_result.authenticationToken
|
31
|
+
note_store_url = "#{NOTE_STORE_URL}/#{user.shardId}"
|
32
|
+
@note_store = Evernote::NoteStore.new(note_store_url)
|
33
|
+
log.info "Evernote authentication was successful for #{Colors::USER} #{params[:username]}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def sync
|
37
|
+
return unless authenticated?
|
38
|
+
unless File.directory?(@path)
|
39
|
+
log.error("#{@path}' is not a directory!")
|
40
|
+
return
|
41
|
+
end
|
42
|
+
|
43
|
+
log.info "synchronizing with Evernote account..."
|
44
|
+
log.indent(2) do
|
45
|
+
# create notebook directories
|
46
|
+
fetch_notebooks.each do |notebook|
|
47
|
+
notebook_path = get_notebook_path(notebook[:name])
|
48
|
+
FileUtils.mkdir(notebook_path) unless File.exists?(notebook_path)
|
49
|
+
|
50
|
+
# write notes to files
|
51
|
+
notebook[:notes].each do |note|
|
52
|
+
note_path = get_note_path(notebook_path, note[:title])
|
53
|
+
File.open(note_path, 'w') { |f| f << note[:content] }
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.sanitize_evernote(path)
|
60
|
+
html = File.read(path)
|
61
|
+
Sanitize.clean(html)
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
def fetch_notebooks
|
67
|
+
notebooks = @note_store.listNotebooks(@token) || []
|
68
|
+
log.info "checking for updates..."
|
69
|
+
log.indent(2) do
|
70
|
+
notebooks.map { |notebook| { :name => notebook.name,
|
71
|
+
:guid => notebook.guid,
|
72
|
+
:notes => fetch_notes(:name => notebook.name, :guid => notebook.guid) } }
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def fetch_notes(notebook_params)
|
77
|
+
filter = Evernote::EDAM::NoteStore::NoteFilter.new
|
78
|
+
filter.notebookGuid = notebook_params[:guid]
|
79
|
+
notes = @note_store.findNotes(@token, filter, nil, MAX_NOTES).notes || []
|
80
|
+
log.indent(2) do
|
81
|
+
notes.inject([]) do |notes, note|
|
82
|
+
if needs_update?(notebook_params[:name], note)
|
83
|
+
notes << { :title => note.title, :guid => note.guid, :content => fetch_note_content(note.guid) }
|
84
|
+
else
|
85
|
+
notes
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def fetch_note_content(note_guid)
|
92
|
+
note = @note_store.getNote(@token, note_guid, true, nil, nil, nil)
|
93
|
+
log.info "updating note #{Colors::NOTE} #{note.title} #{Colors::DEFAULT} with content length #{Colors::NUMBER} #{note.contentLength}"
|
94
|
+
note.content
|
95
|
+
end
|
96
|
+
|
97
|
+
def needs_update?(notebook_name, note)
|
98
|
+
local_note_path = get_note_path(get_notebook_path(notebook_name), note.title)
|
99
|
+
return true unless File.exists?(local_note_path)
|
100
|
+
|
101
|
+
evernote_hash = note.contentHash
|
102
|
+
local_note_hash = Digest::MD5.digest(File.read(local_note_path))
|
103
|
+
log.debug "evernote_hash: #{evernote_hash}"
|
104
|
+
log.debug "local_hash: #{local_note_hash}"
|
105
|
+
return evernote_hash != local_note_hash
|
106
|
+
end
|
107
|
+
|
108
|
+
def get_notebook_path(notebook_name)
|
109
|
+
"#{@path}/#{sanitize_filename(notebook_name)}"
|
110
|
+
end
|
111
|
+
|
112
|
+
def get_note_path(notebook_path, note_title)
|
113
|
+
"#{notebook_path}/#{sanitize_filename(note_title)}.#{NOTE_EXT}"
|
114
|
+
end
|
115
|
+
|
116
|
+
def authenticated?
|
117
|
+
!@token.nil?
|
118
|
+
end
|
119
|
+
|
120
|
+
def sanitize_filename(filename)
|
121
|
+
name = filename.strip
|
122
|
+
name.gsub!(/[^0-9A-Za-z-]/, '_')
|
123
|
+
name.gsub!(/_+/, '_')
|
124
|
+
name
|
125
|
+
end
|
126
|
+
|
127
|
+
end
|
data/lib/fuzzy_notes/logger.rb
CHANGED
@@ -5,8 +5,9 @@ class FuzzyNotes::Log
|
|
5
5
|
LOG_LEVEL = 1
|
6
6
|
|
7
7
|
|
8
|
-
def self.init_log(log_level)
|
8
|
+
def self.init_log(log_level, color)
|
9
9
|
@log = BufferedLogger.new(STDOUT, log_level || LOG_LEVEL, default_format)
|
10
|
+
log.disable_color unless color
|
10
11
|
end
|
11
12
|
|
12
13
|
def self.log
|
@@ -16,16 +17,25 @@ class FuzzyNotes::Log
|
|
16
17
|
private
|
17
18
|
|
18
19
|
def self.default_format
|
19
|
-
{ :debug => "$negative DEBUG: $
|
20
|
-
:
|
21
|
-
:
|
22
|
-
:error => "$red ERROR: $white %s" }
|
20
|
+
{ :debug => "$negative DEBUG: $reset %s",
|
21
|
+
:warn => "$yellow WARNING: $reset %s",
|
22
|
+
:error => "$red ERROR: $reset %s" }
|
23
23
|
end
|
24
24
|
|
25
25
|
end
|
26
26
|
|
27
27
|
|
28
28
|
module FuzzyNotes::Logger
|
29
|
+
module Colors
|
30
|
+
PATH = "$blue"
|
31
|
+
USER = "$green"
|
32
|
+
NOTE = "$cyan"
|
33
|
+
NUMBER = "$red"
|
34
|
+
CREATE = "$green"
|
35
|
+
DELETE = "$red"
|
36
|
+
DEFAULT = "$reset"
|
37
|
+
end
|
38
|
+
|
29
39
|
def log
|
30
40
|
FuzzyNotes::Log.log
|
31
41
|
end
|
data/lib/fuzzy_notes/notes.rb
CHANGED
@@ -2,22 +2,26 @@ class FuzzyNotes::Notes
|
|
2
2
|
include FuzzyNotes::Logger
|
3
3
|
|
4
4
|
module Defaults
|
5
|
-
LOG_LEVEL
|
6
|
-
EDITOR='vim'
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
LOG_LEVEL = 1
|
6
|
+
EDITOR = 'vim'
|
7
|
+
COLOR = true
|
8
|
+
KEYWORDS = []
|
9
|
+
NOTE_PATHS = [ "#{ENV['HOME']}/notes" ]
|
10
|
+
VALID_EXTENSIONS = [ 'txt',
|
11
|
+
FuzzyNotes::Cipher::CIPHERTEXT_EXT,
|
12
|
+
FuzzyNotes::Cipher::PLAINTEXT_EXT,
|
13
|
+
FuzzyNotes::EvernoteSync::NOTE_EXT ]
|
10
14
|
|
11
15
|
def self.const_missing(*args); end
|
12
16
|
end
|
13
17
|
|
14
|
-
OPTS = [:log_level, :editor, :note_paths, :valid_extensions, :keywords].freeze
|
18
|
+
OPTS = [:log_level, :color, :editor, :note_paths, :valid_extensions, :keywords, :evernote_params].freeze
|
15
19
|
|
16
20
|
attr_reader :matching_notes, :all_notes
|
17
21
|
|
18
22
|
def initialize(params = {})
|
19
23
|
parse_init_params(params)
|
20
|
-
FuzzyNotes::Log.init_log(@log_level)
|
24
|
+
FuzzyNotes::Log.init_log(@log_level, @color)
|
21
25
|
log.debug "init attributes: \n#{inspect_instance_vars}"
|
22
26
|
|
23
27
|
unless note_paths_valid?
|
@@ -39,7 +43,7 @@ end
|
|
39
43
|
klass = self.class
|
40
44
|
klass.send(:attr_reader, param)
|
41
45
|
default_const = param.to_s.upcase
|
42
|
-
instance_variable_set("@#{param}", params[param]
|
46
|
+
instance_variable_set("@#{param}", params.include?(param) ? params[param] : Defaults.const_get(default_const) )
|
43
47
|
end
|
44
48
|
end
|
45
49
|
private :parse_init_params
|
@@ -50,14 +54,18 @@ end
|
|
50
54
|
matching_notes.each do |note_path|
|
51
55
|
contents = \
|
52
56
|
if encrypted?(note_path)
|
53
|
-
|
57
|
+
log.info "decrypting note #{Colors::PATH} #{note_path}"
|
54
58
|
FuzzyNotes::Cipher.new.decrypt(note_path)
|
59
|
+
elsif evernote?(note_path)
|
60
|
+
FuzzyNotes::EvernoteSync.sanitize_evernote(note_path)
|
55
61
|
else
|
56
62
|
File.read(note_path)
|
57
63
|
end
|
58
64
|
|
59
|
-
|
60
|
-
|
65
|
+
unless contents.blank?
|
66
|
+
log.info "=== #{note_path} ===\n\n"
|
67
|
+
puts "#{contents}\n"
|
68
|
+
end
|
61
69
|
end
|
62
70
|
end
|
63
71
|
|
@@ -70,13 +78,19 @@ end
|
|
70
78
|
# encrypt matching notes
|
71
79
|
#
|
72
80
|
def encrypt
|
73
|
-
|
81
|
+
return if matching_notes.empty?
|
82
|
+
log.info "encrypting matching notes:"
|
83
|
+
print_notes
|
84
|
+
log.indent(2) { FuzzyNotes::Cipher.new.encrypt(matching_notes, :replace => true) }
|
74
85
|
end
|
75
86
|
|
76
87
|
# decrypt matching notes
|
77
88
|
#
|
78
89
|
def decrypt
|
79
|
-
|
90
|
+
return if matching_notes.empty?
|
91
|
+
log.info "decrypting matching notes:"
|
92
|
+
print_notes
|
93
|
+
log.indent(2) { FuzzyNotes::Cipher.new.decrypt(matching_notes, :replace => true) }
|
80
94
|
end
|
81
95
|
|
82
96
|
# view WC info for all/matching notes
|
@@ -86,11 +100,26 @@ end
|
|
86
100
|
puts `wc $(find #{paths} -type f)`
|
87
101
|
end
|
88
102
|
|
103
|
+
def list
|
104
|
+
print_notes(:all => true)
|
105
|
+
end
|
106
|
+
|
107
|
+
def evernote_sync
|
108
|
+
unless @evernote_params
|
109
|
+
log.error("no evernote configuration found!")
|
110
|
+
return
|
111
|
+
end
|
112
|
+
|
113
|
+
log.info "syncing evernote directory #{Colors::PATH} #{@evernote_params[:note_path]}"
|
114
|
+
FuzzyNotes::EvernoteSync.new(@evernote_params).sync
|
115
|
+
log.print_blank_line
|
116
|
+
end
|
117
|
+
|
89
118
|
private
|
90
119
|
|
91
120
|
def note_paths_valid?
|
92
121
|
@note_paths.any? do |p|
|
93
|
-
File.
|
122
|
+
File.directory?(p) || log.warn("note path #{Colors::PATH} #{p} does not exist")
|
94
123
|
end
|
95
124
|
end
|
96
125
|
|
@@ -108,5 +137,13 @@ private
|
|
108
137
|
File.extname(path)[1..-1] == FuzzyNotes::Cipher::CIPHERTEXT_EXT
|
109
138
|
end
|
110
139
|
|
140
|
+
def evernote?(path)
|
141
|
+
File.extname(path)[1..-1] == FuzzyNotes::EvernoteSync::NOTE_EXT
|
142
|
+
end
|
143
|
+
|
144
|
+
def print_notes(params = {})
|
145
|
+
notes = (matching_notes.empty? && params[:all]) ? all_notes : matching_notes
|
146
|
+
log.indent(2) { notes.each { |note| log.info "#{Colors::PATH} #{note}" } }
|
147
|
+
end
|
111
148
|
|
112
149
|
end
|
data/lib/fuzzy_notes.rb
CHANGED
@@ -1,8 +1,11 @@
|
|
1
|
+
require 'pp'
|
1
2
|
require 'rubygems'
|
2
3
|
|
3
4
|
module FuzzyNotes; end
|
4
5
|
|
5
6
|
require 'fuzzy_notes/logger'
|
7
|
+
require 'fuzzy_notes/password_protected'
|
6
8
|
require 'fuzzy_notes/cipher'
|
7
|
-
require 'fuzzy_notes/
|
9
|
+
require 'fuzzy_notes/evernote_sync'
|
8
10
|
require 'fuzzy_notes/fuzzy_finder'
|
11
|
+
require 'fuzzy_notes/notes'
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fuzzy_notes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 17
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 7
|
10
|
+
version: 0.0.7
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Alex Skryl
|
@@ -15,25 +15,27 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-07-
|
18
|
+
date: 2011-07-26 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
22
|
-
name:
|
22
|
+
name: buffered_logger
|
23
23
|
prerelease: false
|
24
24
|
requirement: &id001 !ruby/object:Gem::Requirement
|
25
25
|
none: false
|
26
26
|
requirements:
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
|
-
hash:
|
29
|
+
hash: 31
|
30
30
|
segments:
|
31
31
|
- 0
|
32
|
-
|
32
|
+
- 1
|
33
|
+
- 2
|
34
|
+
version: 0.1.2
|
33
35
|
type: :runtime
|
34
36
|
version_requirements: *id001
|
35
37
|
- !ruby/object:Gem::Dependency
|
36
|
-
name:
|
38
|
+
name: gibberish
|
37
39
|
prerelease: false
|
38
40
|
requirement: &id002 !ruby/object:Gem::Requirement
|
39
41
|
none: false
|
@@ -46,7 +48,35 @@ dependencies:
|
|
46
48
|
version: "0"
|
47
49
|
type: :runtime
|
48
50
|
version_requirements: *id002
|
49
|
-
|
51
|
+
- !ruby/object:Gem::Dependency
|
52
|
+
name: evernote
|
53
|
+
prerelease: false
|
54
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
55
|
+
none: false
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
hash: 3
|
60
|
+
segments:
|
61
|
+
- 0
|
62
|
+
version: "0"
|
63
|
+
type: :runtime
|
64
|
+
version_requirements: *id003
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: sanitize
|
67
|
+
prerelease: false
|
68
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
hash: 3
|
74
|
+
segments:
|
75
|
+
- 0
|
76
|
+
version: "0"
|
77
|
+
type: :runtime
|
78
|
+
version_requirements: *id004
|
79
|
+
description: A note manager with fuzzy path search, full text search, evernote sync, and encryption capabilities
|
50
80
|
email: rut216@gmail.com
|
51
81
|
executables:
|
52
82
|
- fnote
|
@@ -60,6 +90,7 @@ files:
|
|
60
90
|
- lib/fuzzy_notes/fuzzy_finder.rb
|
61
91
|
- lib/fuzzy_notes/logger.rb
|
62
92
|
- lib/fuzzy_notes/notes.rb
|
93
|
+
- lib/fuzzy_notes/password_protected.rb
|
63
94
|
- lib/fuzzy_notes.rb
|
64
95
|
- bin/fnote
|
65
96
|
- README
|
@@ -97,6 +128,6 @@ rubyforge_project:
|
|
97
128
|
rubygems_version: 1.6.2
|
98
129
|
signing_key:
|
99
130
|
specification_version: 3
|
100
|
-
summary: A
|
131
|
+
summary: A cli note manager
|
101
132
|
test_files: []
|
102
133
|
|