na 1.2.87 → 1.2.89

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/plugins.md ADDED
@@ -0,0 +1,38 @@
1
+ I would like to add a plugin architecture to na_gem. It should allow the user to add plugins to ~/.local/share/na/plugins/. These plugins can be any shell script (with a shebang). They can be run with `na plugin NAME`, which accepts the plugin filename with or without an extension, and with or without spaces (so that `plugin AddFoo` will run `Add Foo.sh` if found, but the user can also use `plugin "Add Foo"`).
2
+
3
+ A plugin will be a shell script that takes input on STDIN. The input should be an action as a JSON object, with the file path, line number, action text, note, and array of tags/values (`tags: [{ name: "done", value: "2025-10-29 03:00"}, { name: "na", value: ""}]`). That should be the default.
4
+
5
+ The `plugin` command should accept a `--input TYPE` flag that accepts `json`, `yaml` or `text`. The YAML should be the same as the JSON (but as YAML), and the text should just be the file_path:line_number, action text, and note, split with "||" (newlines in the note replaced with \n, and filename and line number are combined with : not the divider), with no colorization. One action per line. The "||" in `--input text` should also be a flag `--divider "STRING"` that defaults to "||", but allows the user to specify a different string to split the parts on.
6
+
7
+ The plugin will need to return output (on STDOUT) in the same format as the input (yaml, json, or text with specified divider), unless `--output FORMAT` is specified with a different type. The `plugin` command will execute the script for every command passed to it, and update the actions based on the returned output.
8
+
9
+ The `plugin` command should accept all the same filter flags as `finish` or other actions that update commands.
10
+
11
+ For the `update` command, it should accept a `--plugin NAME` flag, and if it's using interactive menus, a list of plugin names (basename minus extension) should be added to the list of available operations.
12
+
13
+ Also add a `--plugin NAME`, `--input TYPE`, and `--output TYPE` flag to all search and display commands (next, grep, tagged, etc.). That way the user can filter output with any command and run the result through the plugin.
14
+
15
+ In lieu of the `--input` and `--output` commands, the plugin itself can have a comment block after the shebang with `key: value` pairs. When reading a plugin, check for a comment block with `input: JSON` `output: YAML` (case insensitive). The user can also define a `name` or `title` (interchangeable) in this block, which will be used instead of the base name if provided. We need to ignore leading characters when scanning for this comment block (e.g. # or //). The block can have blank lines before it. The only keys we read are input, output, and name/title. Parsing stops at the first blank line or after all three keys are populated. Other keys might exist, like `author` or `description`, which should be ignored.
16
+
17
+ The plugins shouldn't need to be executable, the hashbang should be read and used to execute the script.
18
+
19
+ When `na` runs, it should check for the existence of the `plugins` directory, creating it if it's missing, and adding a `~/.local/share/na/plugsin/README.md` file with plugin instructions if one doesn't exist. Any `.md` or `.bak` file in the plugins directory should be ignored. In fact, let's have a helper validate the files in the directory by checking for a shebang and ignoring if none exists, and also ignoring any '.bak' or '.md' files.
20
+
21
+ Have NA also create 2 sample plugins in the `~/.local/share/na/plugins` folder when creating it (do not create plugins if the folder already exists). Have the sample plugins be a Python script and a Bash script. The sample plugins should just do something benign like add a tag with a dynamic value to the passed actions. In the README.md note that the user can delete the sample plugins. Give the sample plugins names "Add Foo.py" and "Add Bar.sh" and have them add @foo and @bar, respectively.
22
+
23
+ ### Summary ###
24
+
25
+ - plugins are script files in ~/.local/share/na/plugins
26
+ - plugins require a shebang, which is used to execute them
27
+ - plugin base names (without extension) becomes the command name (spaces are handled)
28
+ - Ignore
29
+ - `plugin` subcommand
30
+ - accepts plugin name as argument
31
+ - has a `--input TYPE` flag that determines the input type (yaml, json, or text)
32
+ - has a `--output TYPE` (yaml, json, or text)
33
+ - has a `--divider` flag that determines the divider when `--input text` is used
34
+ - `update` subcommand
35
+ - accepts a `--plugin NAME` flag
36
+ - Adds plugin names to interactive menu when no action is specified
37
+ - main script parses the output of the plugin, stripping whitespace and reading it as YAML, JSON, or text split on the divider (based on `--output` and defaulting to the value of `--input`), then updates each action in the result. Line numbers should be passed on both input and output and used to update the specific actions.
38
+ - Generate README and scripts
data/src/_README.md CHANGED
@@ -9,7 +9,50 @@
9
9
  _If you're one of the rare people like me who find this useful, feel free to
10
10
  [buy me some coffee][donate]._
11
11
 
12
- The current version of `na` is <!--VER-->1.2.86<!--END VER-->.
12
+ The current version of `na` is <!--VER-->1.2.88<!--END VER-->.
13
+
14
+ <!--GITHUB-->
15
+ ### Table of contents
16
+
17
+ - [Installation](#installation)
18
+ - [Optional Dependencies](#optional-dependencies)
19
+ - [Features](#features)
20
+ - [Easy matching](#easy-matching)
21
+ - [Recursion](#recursion)
22
+ - [Adding todos](#adding-todos)
23
+ - [Updating todos](#updating-todos)
24
+ - [Terminology](#terminology)
25
+ - [Usage](#usage)
26
+ - [Commands](#commands)
27
+ - [add](#add)
28
+ - [edit](#edit)
29
+ - [find](#find)
30
+ - [init, create](#init-create)
31
+ - [move](#move)
32
+ - [next, show](#next-show)
33
+ - [plugin](#plugin)
34
+ - [projects](#projects)
35
+ - [saved](#saved)
36
+ - [scan](#scan)
37
+ - [tagged](#tagged)
38
+ - [todos](#todos)
39
+ - [update](#update)
40
+ - [changelog](#changelog)
41
+ - [complete](#complete)
42
+ - [archive](#archive)
43
+ - [tag](#tag)
44
+ - [undo](#undo)
45
+ - [Configuration](#configuration)
46
+ - [Working with a single global file](#working-with-a-single-global-file)
47
+ - [Add tasks at the end of a project](#add-tasks-at-the-end-of-a-project)
48
+ - [Prompt Hooks](#prompt-hooks)
49
+ - [Time tracking](#time-tracking)
50
+ - [Plugins](#plugins)
51
+ - [Changelog](#changelog)
52
+ <!--END GITHUB--><!--JEKYLL
53
+ - Table of Contents
54
+ {:.toc}
55
+ -->
13
56
 
14
57
  `na` ("next action") is a command line tool designed to make it easy to see what your next actions are for any project, right from the command line. It works with TaskPaper-formatted files (but any plain text format will do), looking for `@na` tags (or whatever you specify) in todo files in your current folder.
15
58
 
@@ -140,6 +183,54 @@ To see all next actions across all known todos, use `na next "*"`. You can combi
140
183
  @cli(bundle exec bin/na help next)
141
184
  ```
142
185
 
186
+ ##### plugin
187
+
188
+ Manage and run external plugins. See also the Plugins section below.
189
+
190
+ ```
191
+ @cli(bundle exec bin/na help plugin)
192
+ ```
193
+
194
+ ###### plugin new
195
+
196
+ Create a new plugin script (aliases: `n`). Infers shebang by extension or `--language`.
197
+
198
+ ```
199
+ @cli(bundle exec bin/na help plugin new)
200
+ ```
201
+
202
+ ###### plugin edit
203
+
204
+ Open an existing plugin in your default editor. Prompts if no name is given.
205
+
206
+ ```
207
+ @cli(bundle exec bin/na help plugin edit)
208
+ ```
209
+
210
+ ###### plugin run
211
+
212
+ Run a plugin on selected actions (aliases: `x`). Supports input/output format flags and filters.
213
+
214
+ ```
215
+ @cli(bundle exec bin/na help plugin run)
216
+ ```
217
+
218
+ ###### plugin enable
219
+
220
+ Move a plugin from `plugins_disabled` to `plugins` (alias: `e`).
221
+
222
+ ```
223
+ @cli(bundle exec bin/na help plugin enable)
224
+ ```
225
+
226
+ ###### plugin disable
227
+
228
+ Move a plugin from `plugins` to `plugins_disabled` (alias: `d`).
229
+
230
+ ```
231
+ @cli(bundle exec bin/na help plugin disable)
232
+ ```
233
+
143
234
  ##### projects
144
235
 
145
236
  List all projects in a file. If arguments are provided, they're used to match a todo file from history, otherwise the todo file(s) in the current directory will be used.
@@ -235,49 +326,6 @@ See the help output for a list of all available actions.
235
326
  @cli(bundle exec bin/na help update)
236
327
  ```
237
328
 
238
- #### Time tracking
239
-
240
- `na` supports tracking elapsed time between a start and finish for actions using `@started(YYYY-MM-DD HH:MM)` and `@done(YYYY-MM-DD HH:MM)` tags. Durations are not stored; they are calculated on the fly from these tags.
241
-
242
- - Add/Finish/Update flags:
243
- - `--started TIME` set a start time when creating or finishing an item
244
- - `--end TIME` (alias `--finished`) set a done time
245
- - `--duration DURATION` backfill start time from the provided end time
246
- - All flags accept natural language (via Chronic) and shorthand: `30m ago`, `-2h`, `2h30m`, `2:30 ago`, `yesterday 5pm`
247
-
248
- Examples:
249
-
250
- ```bash
251
- na add --started "30 minutes ago" "Investigate bug"
252
- na complete --finished now --duration 2h30m "Investigate bug"
253
- na update --started "yesterday 3pm" --end "yesterday 5:15pm" "Investigate bug"
254
- ```
255
-
256
- - Display flags (next/tagged):
257
- - `--times` show per‑action durations and a grand total (implies `--done`)
258
- - `--human` format durations as human‑readable text instead of `DD:HH:MM:SS`
259
- - `--only_timed` show only actions that have both `@started` and `@done` (implies `--times --done`)
260
- - `--only_times` output only the totals section (no action lines; implies `--times --done`)
261
- - `--json_times` output a JSON object with timed items, per‑tag totals, and overall total (implies `--times --done`)
262
-
263
- Example outputs:
264
-
265
- ```bash
266
- # Per‑action durations appended and totals table
267
- na next --times --human
268
-
269
- # Only totals table (Markdown), no action lines
270
- na tagged "tag*=bug" --only_times
271
-
272
- # JSON for scripting
273
- na next --json_times > times.json
274
- ```
275
-
276
- Notes:
277
-
278
- - Any newly added or edited action text is scanned for natural‑language values in `@started(...)`/`@done(...)` and normalized to `YYYY‑MM‑DD HH:MM`.
279
- - The color of durations in output is configurable via the theme key `duration` (defaults to `{y}`).
280
-
281
329
  ##### changelog
282
330
 
283
331
  View recent changes with `na changelog` or `na changes`.
@@ -375,6 +423,154 @@ If you're using a single global file, you'll need `--cwd_as` to be `tag` or `pro
375
423
 
376
424
  After installing a hook, you'll need to close your terminal and start a new session to initialize the new commands.
377
425
 
426
+ ### Time tracking
427
+
428
+ `na` supports tracking elapsed time between a start and finish for actions using `@started(YYYY-MM-DD HH:MM)` and `@done(YYYY-MM-DD HH:MM)` tags. Durations are not stored; they are calculated on the fly from these tags.
429
+
430
+ - Add/Finish/Update flags:
431
+ - `--started TIME` set a start time when creating or finishing an item
432
+ - `--end TIME` (alias `--finished`) set a done time
433
+ - `--duration DURATION` backfill start time from the provided end time
434
+ - All flags accept natural language (via Chronic) and shorthand: `30m ago`, `-2h`, `2h30m`, `2:30 ago`, `yesterday 5pm`
435
+
436
+ Examples:
437
+
438
+ ```bash
439
+ na add --started "30 minutes ago" "Investigate bug"
440
+ na complete --finished now --duration 2h30m "Investigate bug"
441
+ na update --started "yesterday 3pm" --end "yesterday 5:15pm" "Investigate bug"
442
+ ```
443
+
444
+ - Display flags (next/tagged):
445
+ - `--times` show per‑action durations and a grand total (implies `--done`)
446
+ - `--human` format durations as human‑readable text instead of `DD:HH:MM:SS`
447
+ - `--only_timed` show only actions that have both `@started` and `@done` (implies `--times --done`)
448
+ - `--only_times` output only the totals section (no action lines; implies `--times --done`)
449
+ - `--json_times` output a JSON object with timed items, per‑tag totals, and overall total (implies `--times --done`)
450
+
451
+ Example outputs:
452
+
453
+ ```bash
454
+ # Per‑action durations appended and totals table
455
+ na next --times --human
456
+
457
+ # Only totals table (Markdown), no action lines
458
+ na tagged "tag*=bug" --only_times
459
+
460
+ # JSON for scripting
461
+ na next --json_times > times.json
462
+ ```
463
+
464
+ Notes:
465
+
466
+ - Any newly added or edited action text is scanned for natural‑language values in `@started(...)`/`@done(...)` and normalized to `YYYY‑MM‑DD HH:MM`.
467
+ - The color of durations in output is configurable via the theme key `duration` (defaults to `{y}`).
468
+
469
+ ### Plugins
470
+
471
+ NA supports a plugin system that allows you to run external scripts to transform or process actions. Plugins are stored in `~/.local/share/na/plugins` and can be written in any language with a shebang.
472
+
473
+ #### Getting Started
474
+
475
+ The first time NA runs, it will create the plugins directory with a README and two sample plugins:
476
+ - `Add Foo.py` - Adds a `@foo` tag with a timestamp
477
+ - `Add Bar.sh` - Adds a `@bar` tag
478
+
479
+ You can delete or modify these sample plugins as needed.
480
+
481
+ #### Running Plugins
482
+
483
+ You can manage and run plugins using subcommands under `na plugin`:
484
+
485
+ - `new`/`n`: scaffold a new plugin script
486
+ - `edit`: open an existing plugin
487
+ - `run`/`x`: run a plugin against selected actions
488
+ - `enable`/`e`: move from disabled to enabled
489
+ - `disable`/`d`: move from enabled to disabled
490
+
491
+ Plugins are executed with actions on STDIN and must return actions on STDOUT. Display commands can still pipe through plugins via `--plugin`, which only affects STDOUT (no writes).
492
+
493
+ #### Plugin Metadata
494
+
495
+ Plugins can specify their behavior in a metadata block after the shebang:
496
+
497
+ ```bash
498
+ #!/usr/bin/env python3
499
+ # name: My Plugin
500
+ # input: json
501
+ # output: json
502
+ ```
503
+
504
+ Available metadata keys (case-insensitive):
505
+ - `input`: Input format (`json`, `yaml`, `csv`, `text`)
506
+ - `output`: Output format
507
+ - `name` or `title`: Display name (defaults to filename)
508
+
509
+ #### Input/Output Formats
510
+
511
+ Plugins accept and return action data. Use `--input` and `--output` flags to override metadata:
512
+
513
+ ```bash
514
+ na plugin MY_PLUGIN --input text --output json --divider "||"
515
+ ```
516
+
517
+ **JSON/YAML Schema:**
518
+ ```json
519
+ [
520
+ {
521
+ "file_path": "todo.taskpaper",
522
+ "line": 15,
523
+ "parents": ["Project", "Subproject"],
524
+ "text": "- Action text @tag(value)",
525
+ "note": "Note content",
526
+ "tags": [
527
+ { "name": "tag", "value": "value" }
528
+ ]
529
+ }
530
+ ]
531
+ ```
532
+
533
+ **Text Format:**
534
+ ```
535
+ ACTION||ARGS||file_path:line||parents||text||note||tags
536
+ ```
537
+
538
+ Default divider is `||` (configurable with `--divider`).
539
+ - `parents`: `Parent>Child>Leaf`
540
+ - `tags`: `name(value);name;other(value)`
541
+
542
+ If the first token isn’t a known action, it’s treated as `file_path:line` and the action defaults to UPDATE.
543
+
544
+ #### Actions
545
+
546
+ Plugins may return an optional ACTION with arguments. Supported (case-insensitive):
547
+ - UPDATE (default; replace text/note/tags/parents)
548
+ - DELETE
549
+ - COMPLETE/FINISH
550
+ - RESTORE/UNFINISH
551
+ - ARCHIVE
552
+ - ADD_TAG (args: one or more tags)
553
+ - DELETE_TAG/REMOVE_TAG (args: one or more tags)
554
+ - MOVE (args: target project path)
555
+
556
+ #### Plugin Behavior
557
+
558
+ **On `update` or `plugin` command:**
559
+ - Plugins can modify text, notes, tags, and parents
560
+ - Changing `parents` will move the action to the new project location
561
+ - `file_path` and `line` cannot be changed
562
+
563
+ **On display commands (`next`, `tagged`, `find`):**
564
+ - Plugins only transform STDOUT (no file writes)
565
+ - Use returned text/note/tags/parents for rendering
566
+ - Parent changes affect display but not file structure
567
+
568
+ #### Override Formats
569
+
570
+ You can override plugin defaults with flags on any command that supports `--plugin`:
571
+ ```bash
572
+ na next --plugin FOO --input csv --output text
573
+ ```
378
574
 
379
575
  [fzf]: https://github.com/junegunn/fzf
380
576
  [gum]: https://github.com/charmbracelet/gum
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: na
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.87
4
+ version: 1.2.89
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra
@@ -57,6 +57,20 @@ dependencies:
57
57
  - - ">="
58
58
  - !ruby/object:Gem::Version
59
59
  version: 0.10.2
60
+ - !ruby/object:Gem::Dependency
61
+ name: csv
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - ">="
65
+ - !ruby/object:Gem::Version
66
+ version: '3.2'
67
+ type: :runtime
68
+ prerelease: false
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '3.2'
60
74
  - !ruby/object:Gem::Dependency
61
75
  name: git
62
76
  requirement: !ruby/object:Gem::Requirement
@@ -269,6 +283,7 @@ files:
269
283
  - bin/commands/move.rb
270
284
  - bin/commands/next.rb
271
285
  - bin/commands/open.rb
286
+ - bin/commands/plugin.rb
272
287
  - bin/commands/projects.rb
273
288
  - bin/commands/prompt.rb
274
289
  - bin/commands/restore.rb
@@ -299,6 +314,7 @@ files:
299
314
  - lib/na/help_monkey_patch.rb
300
315
  - lib/na/next_action.rb
301
316
  - lib/na/pager.rb
317
+ - lib/na/plugins.rb
302
318
  - lib/na/project.rb
303
319
  - lib/na/prompt.rb
304
320
  - lib/na/string.rb
@@ -308,6 +324,9 @@ files:
308
324
  - lib/na/version.rb
309
325
  - na.gemspec
310
326
  - na.rdoc
327
+ - na/Test.todo.markdown
328
+ - na/test.md
329
+ - plugins.md
311
330
  - scripts/fixreadme.rb
312
331
  - scripts/generate-fish-completions.rb
313
332
  - scripts/runtests.sh