thor-osc7501 0.1.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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +12 -0
- data/CONTRIBUTING.md +40 -0
- data/LICENSE +201 -0
- data/README.md +88 -0
- data/examples/Thorfile +38 -0
- data/lib/thor/osc7501/hooks.rb +117 -0
- data/lib/thor/osc7501/run.rb +134 -0
- data/lib/thor/osc7501/version.rb +9 -0
- data/lib/thor/osc7501/writer.rb +67 -0
- data/lib/thor/osc7501.rb +14 -0
- data/sig/thor/osc7501/hooks.rbs +63 -0
- data/sig/thor/osc7501/run.rbs +59 -0
- data/sig/thor/osc7501/version.rbs +8 -0
- data/sig/thor/osc7501/writer.rbs +31 -0
- data/sig/thor/osc7501.rbs +9 -0
- metadata +72 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 1774a0a472abc4cc8b707ce62db5fbd78d5e31fb59e1e5816e567df2396c3c4d
|
|
4
|
+
data.tar.gz: 0a8045f44d2890953f16bfd6964b71d5c337f40849e46a6c3c86f97f844ad7af
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: c008b9a3fee66fc44c1504b3a59658eba18f75ee636caa16852d0338f8b6d7a9f8b97c2923334ebbb724f6d370212d17c10549c36a4c1dfdbbbfeb8b6e609580
|
|
7
|
+
data.tar.gz: a2f005c1e85162b0fefceae918fe4276d73062bf6a41986ace8c1a02e077d7ce9eb58543afe5b957383bc4eed31ec84446c355b03983151bec36e95e66553a97
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## Unreleased
|
|
4
|
+
|
|
5
|
+
## 0.1.0 - 2026-11-13
|
|
6
|
+
|
|
7
|
+
- init ([8d8fc45](https://github.com/cosgroveb/thor-osc7501/commit/8d8fc45f2577583c4e60d32ed7dcc3a047ddd7e1))
|
|
8
|
+
- Add Thor OSC 7501 command and prompt reporting ([a2a2ebe](https://github.com/cosgroveb/thor-osc7501/commit/a2a2ebeed2235b53133a455b91b781b25c27453e))
|
|
9
|
+
- Add release machinery matching the sibling gems ([8f6d8ae](https://github.com/cosgroveb/thor-osc7501/commit/8f6d8ae880b65cb77992ef6d07e90f02dadaa67b))
|
|
10
|
+
- Retain credentials for release preparation ([4f4a4a7](https://github.com/cosgroveb/thor-osc7501/commit/4f4a4a740457be34ad7a64ef58784a2b8348758e))
|
|
11
|
+
- Fix release matrix defaults and smoke checks ([bd3c2f0](https://github.com/cosgroveb/thor-osc7501/commit/bd3c2f06e2b250739e0d7e3937feb758cd36ce8b))
|
|
12
|
+
- Normalize temporary paths across platforms ([fe24a90](https://github.com/cosgroveb/thor-osc7501/commit/fe24a90c45f9931ab7c7f8b7ce62ef9a8c7e4e4e))
|
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# Contributing
|
|
2
|
+
|
|
3
|
+
AI-assisted contributions are welcome. Before requesting review, understand
|
|
4
|
+
the changes, run relevant checks, and verify claims in code, documentation,
|
|
5
|
+
and reports. State what you tested and what remains uncertain. Be prepared
|
|
6
|
+
to explain your choices and address feedback. When using an agent to help
|
|
7
|
+
answer a reviewer, check the answer and send only what is relevant.
|
|
8
|
+
|
|
9
|
+
Use MRI Ruby 3.4 or newer for development tooling, then run all checks:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
bundle install
|
|
13
|
+
bundle exec rake
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The default task runs inline RBS checks with Steep, the specs and
|
|
17
|
+
installed-gem smoke tests. Run `bundle exec rake types`, `spec`, `package`
|
|
18
|
+
or `smoke` for individual checks.
|
|
19
|
+
|
|
20
|
+
`rake types` validates that every authored file opts into inline RBS, every
|
|
21
|
+
method carries a `#:` annotation, and Steep accepts the runtime and tooling
|
|
22
|
+
implementations in `lib/` and `script/` against the generated signatures.
|
|
23
|
+
Keep project types inline. `untyped` is accepted at the Thor framework
|
|
24
|
+
boundary but not as a substitute for known types. `sig/dependencies.rbs`
|
|
25
|
+
fills gaps in dependency signatures, including the `CommandHook` module
|
|
26
|
+
self type that rbs-inline cannot emit. Generated signatures live only in
|
|
27
|
+
ignored `tmp/` during development and inside the built gem under `sig/`,
|
|
28
|
+
never in the source tree.
|
|
29
|
+
|
|
30
|
+
Keep the runtime dependency limited to `thor`. Cover command, nesting and
|
|
31
|
+
prompt behavior with real Thor subprocesses: fixtures in `spec/support` run
|
|
32
|
+
isolated processes with bounded timeouts and reap every child. PTY fixtures
|
|
33
|
+
synchronize on observed state, not sleeps. Compatibility runs use
|
|
34
|
+
`Gemfile.compat` with pinned `THOR_VERSION` and `RSPEC_MINOR` on the oldest
|
|
35
|
+
supported Rubies. Do not load modern development tooling into Ruby 2.1
|
|
36
|
+
runtime checks.
|
|
37
|
+
|
|
38
|
+
Specs run in random order and report their seed. Reproduce an ordering
|
|
39
|
+
failure with `bundle exec rspec --seed <seed>` and narrow it with
|
|
40
|
+
`bundle exec rspec --seed <seed> --bisect`.
|
data/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
data/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# thor-osc7501
|
|
2
|
+
|
|
3
|
+
Add OSC 7501 terminal status to ordinary Thor commands.
|
|
4
|
+
|
|
5
|
+
```ruby
|
|
6
|
+
# Gemfile
|
|
7
|
+
gem 'thor-osc7501', require: false
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
```ruby
|
|
11
|
+
# Thorfile
|
|
12
|
+
require 'thor/osc7501'
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Run `bundle exec thor deploy`. A supporting terminal receives the run as its
|
|
16
|
+
root record with the current command and outcome. Each new run replaces it,
|
|
17
|
+
and ordinary command output, input, return values and exits continue
|
|
18
|
+
unchanged. A Ruby executable can require the same entrypoint before its CLI
|
|
19
|
+
class starts. `Klass.start` works the same way. Installing the gem alone
|
|
20
|
+
does not activate it.
|
|
21
|
+
|
|
22
|
+
## What is reported
|
|
23
|
+
|
|
24
|
+
One root record per outer run, `app=thor`, no identity and no percentage.
|
|
25
|
+
Reporting starts when the first command executes. Sequential nesting shows
|
|
26
|
+
the executing leaf command and restores its caller on return. Overlapping
|
|
27
|
+
commands show `N active commands`. Framework `help`, `list` and `version`
|
|
28
|
+
operations never count as work, while user commands with those names report
|
|
29
|
+
normally. Skipped invocations produce no records.
|
|
30
|
+
|
|
31
|
+
During `ask`, `yes?` or `no?`, the run reports `blocked` attention with the
|
|
32
|
+
prompt text (`kind=question`). Pending prompts take priority over working
|
|
33
|
+
commands. With several prompts pending, the most recently entered one shows
|
|
34
|
+
and the previous one resumes when it resolves. Entered answers are never
|
|
35
|
+
reported. After input returns, the current working status resumes.
|
|
36
|
+
|
|
37
|
+
Normal outer completion reports `done`. An escaping exception or
|
|
38
|
+
unsuccessful `SystemExit` reports `error`, and `Interrupt` or successful
|
|
39
|
+
`SystemExit` reports `idle`, preserving Thor's behavior. Errors handled
|
|
40
|
+
inside an enclosing command body do not finalize the run. Command return
|
|
41
|
+
values never imply success or failure.
|
|
42
|
+
|
|
43
|
+
## Output controls
|
|
44
|
+
|
|
45
|
+
| Setting | Behavior |
|
|
46
|
+
| --- | --- |
|
|
47
|
+
| `THOR_OSC7501=auto` | Default. Report to stdout only when it is a TTY and `TERM` is not `dumb`. |
|
|
48
|
+
| `THOR_OSC7501=force` | Report to stdout even when redirected. |
|
|
49
|
+
| `THOR_OSC7501=off` | Disable Thor reporting. |
|
|
50
|
+
| any other value | Raise `ArgumentError`. |
|
|
51
|
+
|
|
52
|
+
Reporting IO failures disable reporting without replacing the command's own
|
|
53
|
+
exception or result. Messages are sanitized to a single plain-text line and
|
|
54
|
+
capped at 2048 decoded UTF-8 bytes. The ordinary terminal prompt is
|
|
55
|
+
unchanged.
|
|
56
|
+
|
|
57
|
+
## Boundaries
|
|
58
|
+
|
|
59
|
+
Observation covers Thor dispatch: normal CLI loading, direct `Klass.start`
|
|
60
|
+
and nested `invoke`, plus `Thor::Group` sequences through the same path.
|
|
61
|
+
Direct Ruby method calls that bypass Thor dispatch are outside scope.
|
|
62
|
+
Prompt coverage extends to `Thor::Shell::Basic`, `Color` and subclasses that
|
|
63
|
+
retain normal prompt behavior, including shells created before activation. A
|
|
64
|
+
custom shell overriding `ask` directly, or direct stdin reads, are outside
|
|
65
|
+
guaranteed coverage.
|
|
66
|
+
|
|
67
|
+
The concurrency guarantee covers overlapping invocations belonging to one
|
|
68
|
+
outer run. Unrelated simultaneous top-level starts, detached work outliving
|
|
69
|
+
the command, fork coordination and asynchronous frameworks are outside
|
|
70
|
+
first-release guarantees. Synchronous subprocesses keep the run working. We
|
|
71
|
+
do not inspect their output or auto-enable companion reporters, and an
|
|
72
|
+
independently enabled root reporter in a child can overwrite the shared root
|
|
73
|
+
record.
|
|
74
|
+
|
|
75
|
+
## Compatibility and development
|
|
76
|
+
|
|
77
|
+
MRI >= 2.1 and Thor >= 0.19.4, with no speculative upper bound. Development
|
|
78
|
+
requires a modern Ruby only for tooling:
|
|
79
|
+
|
|
80
|
+
```sh
|
|
81
|
+
bundle install
|
|
82
|
+
bundle exec rake
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
The default task checks inline RBS with Steep, runs the specs and exercises
|
|
86
|
+
the packaged gem in an isolated environment. `bundle exec rspec` runs the
|
|
87
|
+
specs alone. See [CONTRIBUTING.md](CONTRIBUTING.md) for the development
|
|
88
|
+
workflow and [CHANGELOG.md](CHANGELOG.md) for changes.
|
data/examples/Thorfile
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
# A tiny generic Thor CLI that exercises OSC 7501 reporting: work, nested
|
|
5
|
+
# work, a confirmation prompt, then completion. Run with:
|
|
6
|
+
# bundle exec thor deploy
|
|
7
|
+
# and compare against THOR_OSC7501=off. A failing command and Ctrl-C show
|
|
8
|
+
# the error and idle outcomes.
|
|
9
|
+
require 'thor/osc7501'
|
|
10
|
+
|
|
11
|
+
class Deploy < Thor
|
|
12
|
+
default_task :deploy
|
|
13
|
+
|
|
14
|
+
desc 'deploy', 'Work, confirm, then finish'
|
|
15
|
+
def deploy
|
|
16
|
+
say 'preparing'
|
|
17
|
+
sleep 1
|
|
18
|
+
invoke :health
|
|
19
|
+
proceed = yes? 'Proceed with release?'
|
|
20
|
+
raise 'declined' unless proceed
|
|
21
|
+
say 'releasing'
|
|
22
|
+
sleep 1
|
|
23
|
+
say 'done'
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
desc 'health', 'Nested work example'
|
|
27
|
+
def health
|
|
28
|
+
say 'checking'
|
|
29
|
+
sleep 1
|
|
30
|
+
say 'healthy'
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
desc 'fail', 'Failure variant'
|
|
34
|
+
def fail
|
|
35
|
+
say 'preparing'
|
|
36
|
+
raise 'boom'
|
|
37
|
+
end
|
|
38
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
require 'thor'
|
|
5
|
+
require_relative 'run'
|
|
6
|
+
|
|
7
|
+
class Thor
|
|
8
|
+
module OSC7501
|
|
9
|
+
# Prepended to Thor::Command: wraps executed commands in Run
|
|
10
|
+
# contexts. Hooking Command#run sits after Thor's invocation
|
|
11
|
+
# deduplication, so skipped commands produce no records. Late
|
|
12
|
+
# prepending the Base module alone would not reach existing
|
|
13
|
+
# includers (verified on Ruby 2.1 during research). The module's
|
|
14
|
+
# self type is declared in sig/dependencies.rbs: rbs-inline cannot
|
|
15
|
+
# emit it.
|
|
16
|
+
module CommandHook
|
|
17
|
+
#: [T] (untyped instance, *untyped args) { (*untyped) -> T } -> T
|
|
18
|
+
def run(instance, *args, &block)
|
|
19
|
+
return super if OSC7501.framework_command?(self)
|
|
20
|
+
run = OSC7501.current_run
|
|
21
|
+
if run
|
|
22
|
+
run.during_command(name) { super }
|
|
23
|
+
else
|
|
24
|
+
OSC7501.start_run { |outer| outer.during_command(name) { super } }
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# Prepended to Thor::Base-derived classes' singleton classes: owns the
|
|
30
|
+
# single root record for the outer run. Nested .start calls and nested
|
|
31
|
+
# dispatches reuse the active run.
|
|
32
|
+
module StartHook
|
|
33
|
+
#: [T] (*untyped args) { (*untyped) -> T } -> T
|
|
34
|
+
def start(*args, &block)
|
|
35
|
+
return super if OSC7501.current_run
|
|
36
|
+
OSC7501.start_run { super(*args, &block) }
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Prepended to Thor::Shell::Basic: reports pending prompts on the
|
|
41
|
+
# configured shell without replacing it. Covers Basic and subclasses
|
|
42
|
+
# such as Color, including shells created before activation. Shells
|
|
43
|
+
# overriding ask directly are outside guaranteed coverage.
|
|
44
|
+
module ShellHook
|
|
45
|
+
#: [T] (untyped statement, *untyped args) { (*untyped) -> T } -> T
|
|
46
|
+
def ask(statement, *args, &block)
|
|
47
|
+
run = OSC7501.current_run
|
|
48
|
+
if run
|
|
49
|
+
run.during_prompt(statement.to_s) { super(statement, *args, &block) }
|
|
50
|
+
else
|
|
51
|
+
super
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# Prepended to Thor::Base's singleton class: hooks classes that
|
|
57
|
+
# include Thor::Base after activation.
|
|
58
|
+
module IncludeHook
|
|
59
|
+
#: (Class base) -> void
|
|
60
|
+
def included(base)
|
|
61
|
+
super
|
|
62
|
+
return unless base.is_a?(Class)
|
|
63
|
+
return if base.singleton_class.ancestors.include?(StartHook)
|
|
64
|
+
base.singleton_class.prepend(StartHook)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Framework-owned commands never count as application work.
|
|
69
|
+
FRAMEWORK_COMMANDS = %w[help list version install installed update uninstall tree].freeze
|
|
70
|
+
|
|
71
|
+
class << self
|
|
72
|
+
# @rbs @installed: bool
|
|
73
|
+
# @rbs @run: Run?
|
|
74
|
+
|
|
75
|
+
#: () -> void
|
|
76
|
+
def install!
|
|
77
|
+
return if @installed
|
|
78
|
+
@installed = true
|
|
79
|
+
Thor::Command.prepend(CommandHook)
|
|
80
|
+
Thor::Base.subclasses.each do |klass|
|
|
81
|
+
next if klass.singleton_class.ancestors.include?(StartHook)
|
|
82
|
+
klass.singleton_class.prepend(StartHook)
|
|
83
|
+
end
|
|
84
|
+
Thor::Base.singleton_class.prepend(IncludeHook)
|
|
85
|
+
Thor::Shell::Basic.prepend(ShellHook)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
#: () -> Run?
|
|
89
|
+
def current_run
|
|
90
|
+
@run
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
#: [T] () { (Run) -> T } -> T
|
|
94
|
+
def start_run
|
|
95
|
+
run = Run.new($stdout, mode: ENV.fetch('THOR_OSC7501', 'auto'))
|
|
96
|
+
previous = @run
|
|
97
|
+
@run = run
|
|
98
|
+
begin
|
|
99
|
+
run.during_run { yield run }
|
|
100
|
+
ensure
|
|
101
|
+
@run = previous
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Framework identity is the command object registered by the Thor
|
|
106
|
+
# framework classes themselves, not the command name: user commands
|
|
107
|
+
# called list or version keep reporting.
|
|
108
|
+
#: (untyped command) -> bool
|
|
109
|
+
def framework_command?(command)
|
|
110
|
+
return false unless FRAMEWORK_COMMANDS.include?(command.name)
|
|
111
|
+
return true if command.equal?(Thor.all_commands[command.name])
|
|
112
|
+
return false unless defined?(Thor::Runner)
|
|
113
|
+
command.equal?(Thor::Runner.all_commands[command.name])
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
end
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
require_relative 'writer'
|
|
5
|
+
|
|
6
|
+
class Thor
|
|
7
|
+
module OSC7501
|
|
8
|
+
# Owns the single root record for one outer Thor run: active command
|
|
9
|
+
# contexts, pending prompts and the final outcome. Private to the
|
|
10
|
+
# adapter. Hooks call during_run/during_command/during_prompt.
|
|
11
|
+
class Run # :nodoc: all
|
|
12
|
+
# @rbs @writer: Writer
|
|
13
|
+
# @rbs @mutex: Mutex
|
|
14
|
+
# @rbs @finished: bool
|
|
15
|
+
# @rbs @reported_work: bool
|
|
16
|
+
# @rbs @erred: bool
|
|
17
|
+
# @rbs @stacks: Hash[Thread, Array[String]]
|
|
18
|
+
# @rbs @prompts: Array[[Thread, String]]
|
|
19
|
+
|
|
20
|
+
#: (IO | StringIO output, mode: String) -> void
|
|
21
|
+
def initialize(output, mode:)
|
|
22
|
+
@writer = Writer.new(output, mode: mode)
|
|
23
|
+
@mutex = Mutex.new
|
|
24
|
+
@finished = false
|
|
25
|
+
@reported_work = false
|
|
26
|
+
@erred = false
|
|
27
|
+
@stacks = {}
|
|
28
|
+
@prompts = []
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# A run finalizes only if real work or a prompt was reported:
|
|
32
|
+
# framework-only invocations (help, list, version) produce no
|
|
33
|
+
# records at all. An exception escaping the outermost command
|
|
34
|
+
# marks the run failed even when Thor consumes it at the outer
|
|
35
|
+
# boundary (exit_on_failure? false). Errors handled inside an
|
|
36
|
+
# enclosing command body do not.
|
|
37
|
+
#: [T] () { () -> T } -> T
|
|
38
|
+
def during_run
|
|
39
|
+
result = yield
|
|
40
|
+
finish(@erred ? 'error' : 'done', @erred ? 'Failed' : 'Completed')
|
|
41
|
+
result
|
|
42
|
+
rescue Exception => e # Preserve Thor's handling of Interrupt and SystemExit.
|
|
43
|
+
stopped = e.is_a?(Interrupt) || (e.is_a?(SystemExit) && e.success?)
|
|
44
|
+
finish(stopped ? 'idle' : 'error', stopped ? 'Stopped' : 'Failed')
|
|
45
|
+
raise
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
#: [T] (String) { () -> T } -> T
|
|
49
|
+
def during_command(name)
|
|
50
|
+
stack = (@stacks[Thread.current] ||= [])
|
|
51
|
+
@mutex.synchronize do
|
|
52
|
+
@reported_work = true
|
|
53
|
+
stack << name
|
|
54
|
+
report
|
|
55
|
+
end
|
|
56
|
+
begin
|
|
57
|
+
yield
|
|
58
|
+
rescue Exception
|
|
59
|
+
# Sole-command escape reaches Thor's outer boundary: mark the
|
|
60
|
+
# run failed even if Thor consumes the error there.
|
|
61
|
+
@mutex.synchronize { @erred = true if sole_context?(stack) }
|
|
62
|
+
raise
|
|
63
|
+
ensure
|
|
64
|
+
@mutex.synchronize do
|
|
65
|
+
stack.pop
|
|
66
|
+
@stacks.delete(Thread.current) if stack.empty?
|
|
67
|
+
report
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
#: [T] (String) { () -> T } -> T
|
|
73
|
+
def during_prompt(text)
|
|
74
|
+
# @type var prompt: [Thread, String]
|
|
75
|
+
prompt = [Thread.current, text]
|
|
76
|
+
@mutex.synchronize do
|
|
77
|
+
@reported_work = true
|
|
78
|
+
@prompts << prompt
|
|
79
|
+
report
|
|
80
|
+
end
|
|
81
|
+
begin
|
|
82
|
+
yield
|
|
83
|
+
ensure
|
|
84
|
+
@mutex.synchronize do
|
|
85
|
+
@prompts.delete(prompt)
|
|
86
|
+
report
|
|
87
|
+
end
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
private
|
|
92
|
+
|
|
93
|
+
#: (String, String) -> void
|
|
94
|
+
def finish(state, message)
|
|
95
|
+
@mutex.synchronize do
|
|
96
|
+
return unless @reported_work
|
|
97
|
+
@finished = true
|
|
98
|
+
@writer.emit(state: state, msg: message)
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Pending prompts take priority over working commands. No default
|
|
103
|
+
# working record is emitted when no command remains active: the
|
|
104
|
+
# run's finalization provides the next record.
|
|
105
|
+
#: () -> void
|
|
106
|
+
def report
|
|
107
|
+
return if @finished
|
|
108
|
+
|
|
109
|
+
prompt = @prompts.last
|
|
110
|
+
if prompt
|
|
111
|
+
@writer.emit(state: 'blocked', msg: prompt[1], kind: 'question')
|
|
112
|
+
return
|
|
113
|
+
end
|
|
114
|
+
active = active_commands
|
|
115
|
+
return if active.empty?
|
|
116
|
+
if active.size == 1
|
|
117
|
+
@writer.emit(state: 'working', msg: active.first.last)
|
|
118
|
+
else
|
|
119
|
+
@writer.emit(state: 'working', msg: "#{active.size} active commands")
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
#: () -> Array[Array[String]]
|
|
124
|
+
def active_commands
|
|
125
|
+
@stacks.values.reject(&:empty?)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
#: (Array[String]) -> bool
|
|
129
|
+
def sole_context?(stack)
|
|
130
|
+
@stacks.values.all? { |other| other.equal?(stack) || other.empty? } && stack.length == 1
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
class Thor
|
|
5
|
+
module OSC7501
|
|
6
|
+
# Encodes status records onto an output stream following the family
|
|
7
|
+
# writer contract. Private to the adapter.
|
|
8
|
+
class Writer # :nodoc: all
|
|
9
|
+
# @rbs @output: IO | StringIO
|
|
10
|
+
# @rbs @enabled: bool
|
|
11
|
+
|
|
12
|
+
#: (IO | StringIO output, mode: String) -> void
|
|
13
|
+
def initialize(output, mode:)
|
|
14
|
+
raise ArgumentError, 'THOR_OSC7501 must be auto, off, or force' unless %w[auto off force].include?(mode)
|
|
15
|
+
|
|
16
|
+
@output = output
|
|
17
|
+
@enabled = mode == 'force' || (mode == 'auto' && automatic_output?)
|
|
18
|
+
rescue IOError, SystemCallError
|
|
19
|
+
@enabled = false
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
#: (state: String, msg: String, ?kind: String?) -> nil
|
|
23
|
+
def emit(state:, msg:, kind: nil)
|
|
24
|
+
return nil unless @enabled
|
|
25
|
+
|
|
26
|
+
fields = ['app=thor', 'title=VGhvcg==', "state=#{state}"]
|
|
27
|
+
fields << "kind=#{kind}" if kind
|
|
28
|
+
fields << "msg=#{encode(msg, 2048)}"
|
|
29
|
+
@output.write("\e]7501;#{fields.join(':')}\e\\")
|
|
30
|
+
@output.flush if @output.respond_to?(:flush)
|
|
31
|
+
nil
|
|
32
|
+
rescue IOError, SystemCallError
|
|
33
|
+
# Reporting failures disable reporting without disturbing the command.
|
|
34
|
+
@enabled = false
|
|
35
|
+
nil
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
private
|
|
39
|
+
|
|
40
|
+
#: () -> bool
|
|
41
|
+
def automatic_output?
|
|
42
|
+
ENV['TERM'] != 'dumb' && @output.respond_to?(:tty?) && @output.tty?
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
#: (String, Integer) -> String
|
|
46
|
+
def encode(text, byte_limit)
|
|
47
|
+
input = text.to_s.byteslice(0, sanitization_byte_limit(byte_limit)) #: String
|
|
48
|
+
plain = input.encode('UTF-8', invalid: :replace, undef: :replace)
|
|
49
|
+
plain = plain.gsub(/\e\[[0-9;?]*[ -\/]*[@-~]/, '')
|
|
50
|
+
plain = plain.gsub(/[\u0000-\u001F\u007F-\u009F]/, ' ')
|
|
51
|
+
clean = plain.gsub(/\s+/, ' ').strip
|
|
52
|
+
bytes = 0
|
|
53
|
+
bounded = clean.each_char.take_while do |char|
|
|
54
|
+
bytes += char.bytesize
|
|
55
|
+
bytes <= byte_limit
|
|
56
|
+
end.join
|
|
57
|
+
[bounded].pack('m0')
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Bound sanitization work with 50% headroom for removed formatting.
|
|
61
|
+
#: (Integer) -> Integer
|
|
62
|
+
def sanitization_byte_limit(output_byte_limit)
|
|
63
|
+
output_byte_limit + output_byte_limit / 2
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
data/lib/thor/osc7501.rb
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# rbs_inline: enabled
|
|
3
|
+
|
|
4
|
+
require_relative 'osc7501/version'
|
|
5
|
+
require_relative 'osc7501/hooks'
|
|
6
|
+
|
|
7
|
+
# Requiring this entrypoint activates Thor OSC 7501 reporting once:
|
|
8
|
+
# ordinary Thor commands and prompts emit terminal status while output,
|
|
9
|
+
# input, return values and exit behavior stay unchanged.
|
|
10
|
+
class Thor
|
|
11
|
+
module OSC7501
|
|
12
|
+
install!
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Generated from lib/thor/osc7501/hooks.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
class Thor
|
|
4
|
+
module OSC7501
|
|
5
|
+
# Prepended to Thor::Command: wraps executed commands in Run
|
|
6
|
+
# contexts. Hooking Command#run sits after Thor's invocation
|
|
7
|
+
# deduplication, so skipped commands produce no records. Late
|
|
8
|
+
# prepending the Base module alone would not reach existing
|
|
9
|
+
# includers (verified on Ruby 2.1 during research). The module's
|
|
10
|
+
# self type is declared in sig/dependencies.rbs: rbs-inline cannot
|
|
11
|
+
# emit it.
|
|
12
|
+
module CommandHook
|
|
13
|
+
# : [T] (untyped instance, *untyped args) { (*untyped) -> T } -> T
|
|
14
|
+
def run: [T] (untyped instance, *untyped args) { (*untyped) -> T } -> T
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
# Prepended to Thor::Base-derived classes' singleton classes: owns the
|
|
18
|
+
# single root record for the outer run. Nested .start calls and nested
|
|
19
|
+
# dispatches reuse the active run.
|
|
20
|
+
module StartHook
|
|
21
|
+
# : [T] (*untyped args) { (*untyped) -> T } -> T
|
|
22
|
+
def start: [T] (*untyped args) { (*untyped) -> T } -> T
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# Prepended to Thor::Shell::Basic: reports pending prompts on the
|
|
26
|
+
# configured shell without replacing it. Covers Basic and subclasses
|
|
27
|
+
# such as Color, including shells created before activation. Shells
|
|
28
|
+
# overriding ask directly are outside guaranteed coverage.
|
|
29
|
+
module ShellHook
|
|
30
|
+
# : [T] (untyped statement, *untyped args) { (*untyped) -> T } -> T
|
|
31
|
+
def ask: [T] (untyped statement, *untyped args) { (*untyped) -> T } -> T
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Prepended to Thor::Base's singleton class: hooks classes that
|
|
35
|
+
# include Thor::Base after activation.
|
|
36
|
+
module IncludeHook
|
|
37
|
+
# : (Class base) -> void
|
|
38
|
+
def included: (Class base) -> void
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Framework-owned commands never count as application work.
|
|
42
|
+
FRAMEWORK_COMMANDS: untyped
|
|
43
|
+
|
|
44
|
+
@installed: bool
|
|
45
|
+
|
|
46
|
+
@run: Run?
|
|
47
|
+
|
|
48
|
+
# : () -> void
|
|
49
|
+
def self.install!: () -> void
|
|
50
|
+
|
|
51
|
+
# : () -> Run?
|
|
52
|
+
def self.current_run: () -> Run?
|
|
53
|
+
|
|
54
|
+
# : [T] () { (Run) -> T } -> T
|
|
55
|
+
def self.start_run: [T] () { (Run) -> T } -> T
|
|
56
|
+
|
|
57
|
+
# Framework identity is the command object registered by the Thor
|
|
58
|
+
# framework classes themselves, not the command name: user commands
|
|
59
|
+
# called list or version keep reporting.
|
|
60
|
+
# : (untyped command) -> bool
|
|
61
|
+
def self.framework_command?: (untyped command) -> bool
|
|
62
|
+
end
|
|
63
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Generated from lib/thor/osc7501/run.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
class Thor
|
|
4
|
+
module OSC7501
|
|
5
|
+
# Owns the single root record for one outer Thor run: active command
|
|
6
|
+
# contexts, pending prompts and the final outcome. Private to the
|
|
7
|
+
# adapter. Hooks call during_run/during_command/during_prompt.
|
|
8
|
+
class Run
|
|
9
|
+
@writer: Writer
|
|
10
|
+
|
|
11
|
+
@mutex: Mutex
|
|
12
|
+
|
|
13
|
+
@finished: bool
|
|
14
|
+
|
|
15
|
+
@reported_work: bool
|
|
16
|
+
|
|
17
|
+
@erred: bool
|
|
18
|
+
|
|
19
|
+
@stacks: Hash[Thread, Array[String]]
|
|
20
|
+
|
|
21
|
+
@prompts: Array[[ Thread, String ]]
|
|
22
|
+
|
|
23
|
+
# : (IO | StringIO output, mode: String) -> void
|
|
24
|
+
def initialize: (IO | StringIO output, mode: String) -> void
|
|
25
|
+
|
|
26
|
+
# A run finalizes only if real work or a prompt was reported:
|
|
27
|
+
# framework-only invocations (help, list, version) produce no
|
|
28
|
+
# records at all. An exception escaping the outermost command
|
|
29
|
+
# marks the run failed even when Thor consumes it at the outer
|
|
30
|
+
# boundary (exit_on_failure? false). Errors handled inside an
|
|
31
|
+
# enclosing command body do not.
|
|
32
|
+
# : [T] () { () -> T } -> T
|
|
33
|
+
def during_run: [T] () { () -> T } -> T
|
|
34
|
+
|
|
35
|
+
# : [T] (String) { () -> T } -> T
|
|
36
|
+
def during_command: [T] (String) { () -> T } -> T
|
|
37
|
+
|
|
38
|
+
# : [T] (String) { () -> T } -> T
|
|
39
|
+
def during_prompt: [T] (String) { () -> T } -> T
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
# : (String, String) -> void
|
|
44
|
+
def finish: (String, String) -> void
|
|
45
|
+
|
|
46
|
+
# Pending prompts take priority over working commands. No default
|
|
47
|
+
# working record is emitted when no command remains active: the
|
|
48
|
+
# run's finalization provides the next record.
|
|
49
|
+
# : () -> void
|
|
50
|
+
def report: () -> void
|
|
51
|
+
|
|
52
|
+
# : () -> Array[Array[String]]
|
|
53
|
+
def active_commands: () -> Array[Array[String]]
|
|
54
|
+
|
|
55
|
+
# : (Array[String]) -> bool
|
|
56
|
+
def sole_context?: (Array[String]) -> bool
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Generated from lib/thor/osc7501/writer.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
class Thor
|
|
4
|
+
module OSC7501
|
|
5
|
+
# Encodes status records onto an output stream following the family
|
|
6
|
+
# writer contract. Private to the adapter.
|
|
7
|
+
class Writer
|
|
8
|
+
@output: IO | StringIO
|
|
9
|
+
|
|
10
|
+
@enabled: bool
|
|
11
|
+
|
|
12
|
+
# : (IO | StringIO output, mode: String) -> void
|
|
13
|
+
def initialize: (IO | StringIO output, mode: String) -> void
|
|
14
|
+
|
|
15
|
+
# : (state: String, msg: String, ?kind: String?) -> nil
|
|
16
|
+
def emit: (state: String, msg: String, ?kind: String?) -> nil
|
|
17
|
+
|
|
18
|
+
private
|
|
19
|
+
|
|
20
|
+
# : () -> bool
|
|
21
|
+
def automatic_output?: () -> bool
|
|
22
|
+
|
|
23
|
+
# : (String, Integer) -> String
|
|
24
|
+
def encode: (String, Integer) -> String
|
|
25
|
+
|
|
26
|
+
# Bound sanitization work with 50% headroom for removed formatting.
|
|
27
|
+
# : (Integer) -> Integer
|
|
28
|
+
def sanitization_byte_limit: (Integer) -> Integer
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# Generated from lib/thor/osc7501.rb with RBS::Inline
|
|
2
|
+
|
|
3
|
+
# Requiring this entrypoint activates Thor OSC 7501 reporting once:
|
|
4
|
+
# ordinary Thor commands and prompts emit terminal status while output,
|
|
5
|
+
# input, return values and exit behavior stay unchanged.
|
|
6
|
+
class Thor
|
|
7
|
+
module OSC7501
|
|
8
|
+
end
|
|
9
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: thor-osc7501
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Brian Cosgrove
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies:
|
|
12
|
+
- !ruby/object:Gem::Dependency
|
|
13
|
+
name: thor
|
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
|
15
|
+
requirements:
|
|
16
|
+
- - ">="
|
|
17
|
+
- !ruby/object:Gem::Version
|
|
18
|
+
version: 0.19.4
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: 0.19.4
|
|
26
|
+
description: Reports Thor command and prompt activity through OSC 7501.
|
|
27
|
+
email:
|
|
28
|
+
- cosgroveb@users.noreply.github.com
|
|
29
|
+
executables: []
|
|
30
|
+
extensions: []
|
|
31
|
+
extra_rdoc_files: []
|
|
32
|
+
files:
|
|
33
|
+
- CHANGELOG.md
|
|
34
|
+
- CONTRIBUTING.md
|
|
35
|
+
- LICENSE
|
|
36
|
+
- README.md
|
|
37
|
+
- examples/Thorfile
|
|
38
|
+
- lib/thor/osc7501.rb
|
|
39
|
+
- lib/thor/osc7501/hooks.rb
|
|
40
|
+
- lib/thor/osc7501/run.rb
|
|
41
|
+
- lib/thor/osc7501/version.rb
|
|
42
|
+
- lib/thor/osc7501/writer.rb
|
|
43
|
+
- sig/thor/osc7501.rbs
|
|
44
|
+
- sig/thor/osc7501/hooks.rbs
|
|
45
|
+
- sig/thor/osc7501/run.rbs
|
|
46
|
+
- sig/thor/osc7501/version.rbs
|
|
47
|
+
- sig/thor/osc7501/writer.rbs
|
|
48
|
+
homepage: https://github.com/cosgroveb/thor-osc7501
|
|
49
|
+
licenses:
|
|
50
|
+
- Apache-2.0
|
|
51
|
+
metadata:
|
|
52
|
+
source_code_uri: https://github.com/cosgroveb/thor-osc7501
|
|
53
|
+
bug_tracker_uri: https://github.com/cosgroveb/thor-osc7501/issues
|
|
54
|
+
changelog_uri: https://github.com/cosgroveb/thor-osc7501/blob/main/CHANGELOG.md
|
|
55
|
+
rdoc_options: []
|
|
56
|
+
require_paths:
|
|
57
|
+
- lib
|
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
59
|
+
requirements:
|
|
60
|
+
- - ">="
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: '2.1'
|
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
68
|
+
requirements: []
|
|
69
|
+
rubygems_version: 3.6.9
|
|
70
|
+
specification_version: 4
|
|
71
|
+
summary: Opt-in OSC 7501 terminal status for Thor commands
|
|
72
|
+
test_files: []
|