@ttctl/cli 0.0.0 → 0.1.0-rc.2
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.
- package/README.md +44 -9
- package/dist/commands/applications/index.d.ts +21 -0
- package/dist/commands/applications/index.d.ts.map +1 -0
- package/dist/commands/applications/index.js +87 -0
- package/dist/commands/applications/index.js.map +1 -0
- package/dist/commands/applications/list.d.ts +55 -0
- package/dist/commands/applications/list.d.ts.map +1 -0
- package/dist/commands/applications/list.js +106 -0
- package/dist/commands/applications/list.js.map +1 -0
- package/dist/commands/applications/shared.d.ts +14 -0
- package/dist/commands/applications/shared.d.ts.map +1 -0
- package/dist/commands/applications/shared.js +19 -0
- package/dist/commands/applications/shared.js.map +1 -0
- package/dist/commands/applications/show.d.ts +51 -0
- package/dist/commands/applications/show.d.ts.map +1 -0
- package/dist/commands/applications/show.js +154 -0
- package/dist/commands/applications/show.js.map +1 -0
- package/dist/commands/applications/stats.d.ts +42 -0
- package/dist/commands/applications/stats.d.ts.map +1 -0
- package/dist/commands/applications/stats.js +69 -0
- package/dist/commands/applications/stats.js.map +1 -0
- package/dist/commands/auth/index.d.ts +17 -0
- package/dist/commands/auth/index.d.ts.map +1 -0
- package/dist/commands/auth/index.js +69 -0
- package/dist/commands/auth/index.js.map +1 -0
- package/dist/commands/auth/init.d.ts +98 -0
- package/dist/commands/auth/init.d.ts.map +1 -0
- package/dist/commands/auth/init.js +387 -0
- package/dist/commands/auth/init.js.map +1 -0
- package/dist/commands/auth/signin.d.ts +81 -0
- package/dist/commands/auth/signin.d.ts.map +1 -0
- package/dist/commands/auth/signin.js +145 -0
- package/dist/commands/auth/signin.js.map +1 -0
- package/dist/commands/auth/signout.d.ts +133 -0
- package/dist/commands/auth/signout.d.ts.map +1 -0
- package/dist/commands/auth/signout.js +172 -0
- package/dist/commands/auth/signout.js.map +1 -0
- package/dist/commands/auth/status.d.ts +62 -0
- package/dist/commands/auth/status.d.ts.map +1 -0
- package/dist/commands/auth/status.js +98 -0
- package/dist/commands/auth/status.js.map +1 -0
- package/dist/commands/availability/allocated-hours.d.ts +27 -0
- package/dist/commands/availability/allocated-hours.d.ts.map +1 -0
- package/dist/commands/availability/allocated-hours.js +61 -0
- package/dist/commands/availability/allocated-hours.js.map +1 -0
- package/dist/commands/availability/index.d.ts +30 -0
- package/dist/commands/availability/index.d.ts.map +1 -0
- package/dist/commands/availability/index.js +124 -0
- package/dist/commands/availability/index.js.map +1 -0
- package/dist/commands/availability/shared.d.ts +11 -0
- package/dist/commands/availability/shared.d.ts.map +1 -0
- package/dist/commands/availability/shared.js +30 -0
- package/dist/commands/availability/shared.js.map +1 -0
- package/dist/commands/availability/show.d.ts +32 -0
- package/dist/commands/availability/show.d.ts.map +1 -0
- package/dist/commands/availability/show.js +86 -0
- package/dist/commands/availability/show.js.map +1 -0
- package/dist/commands/availability/working-hours.d.ts +53 -0
- package/dist/commands/availability/working-hours.d.ts.map +1 -0
- package/dist/commands/availability/working-hours.js +151 -0
- package/dist/commands/availability/working-hours.js.map +1 -0
- package/dist/commands/contracts/index.d.ts +69 -0
- package/dist/commands/contracts/index.d.ts.map +1 -0
- package/dist/commands/contracts/index.js +198 -0
- package/dist/commands/contracts/index.js.map +1 -0
- package/dist/commands/engagements/breaks.d.ts +81 -0
- package/dist/commands/engagements/breaks.d.ts.map +1 -0
- package/dist/commands/engagements/breaks.js +229 -0
- package/dist/commands/engagements/breaks.js.map +1 -0
- package/dist/commands/engagements/index.d.ts +29 -0
- package/dist/commands/engagements/index.d.ts.map +1 -0
- package/dist/commands/engagements/index.js +172 -0
- package/dist/commands/engagements/index.js.map +1 -0
- package/dist/commands/engagements/list.d.ts +49 -0
- package/dist/commands/engagements/list.d.ts.map +1 -0
- package/dist/commands/engagements/list.js +95 -0
- package/dist/commands/engagements/list.js.map +1 -0
- package/dist/commands/engagements/shared.d.ts +10 -0
- package/dist/commands/engagements/shared.d.ts.map +1 -0
- package/dist/commands/engagements/shared.js +31 -0
- package/dist/commands/engagements/shared.js.map +1 -0
- package/dist/commands/engagements/show.d.ts +19 -0
- package/dist/commands/engagements/show.d.ts.map +1 -0
- package/dist/commands/engagements/show.js +150 -0
- package/dist/commands/engagements/show.js.map +1 -0
- package/dist/commands/engagements/stats.d.ts +24 -0
- package/dist/commands/engagements/stats.d.ts.map +1 -0
- package/dist/commands/engagements/stats.js +51 -0
- package/dist/commands/engagements/stats.js.map +1 -0
- package/dist/commands/jobs/index.d.ts +49 -0
- package/dist/commands/jobs/index.d.ts.map +1 -0
- package/dist/commands/jobs/index.js +304 -0
- package/dist/commands/jobs/index.js.map +1 -0
- package/dist/commands/jobs/interest.d.ts +65 -0
- package/dist/commands/jobs/interest.d.ts.map +1 -0
- package/dist/commands/jobs/interest.js +172 -0
- package/dist/commands/jobs/interest.js.map +1 -0
- package/dist/commands/jobs/list.d.ts +81 -0
- package/dist/commands/jobs/list.d.ts.map +1 -0
- package/dist/commands/jobs/list.js +157 -0
- package/dist/commands/jobs/list.js.map +1 -0
- package/dist/commands/jobs/search.d.ts +71 -0
- package/dist/commands/jobs/search.d.ts.map +1 -0
- package/dist/commands/jobs/search.js +163 -0
- package/dist/commands/jobs/search.js.map +1 -0
- package/dist/commands/jobs/shared.d.ts +79 -0
- package/dist/commands/jobs/shared.d.ts.map +1 -0
- package/dist/commands/jobs/shared.js +133 -0
- package/dist/commands/jobs/shared.js.map +1 -0
- package/dist/commands/jobs/show.d.ts +20 -0
- package/dist/commands/jobs/show.d.ts.map +1 -0
- package/dist/commands/jobs/show.js +135 -0
- package/dist/commands/jobs/show.js.map +1 -0
- package/dist/commands/payments/index.d.ts +34 -0
- package/dist/commands/payments/index.d.ts.map +1 -0
- package/dist/commands/payments/index.js +160 -0
- package/dist/commands/payments/index.js.map +1 -0
- package/dist/commands/payments/methods.d.ts +17 -0
- package/dist/commands/payments/methods.d.ts.map +1 -0
- package/dist/commands/payments/methods.js +79 -0
- package/dist/commands/payments/methods.js.map +1 -0
- package/dist/commands/payments/payouts.d.ts +44 -0
- package/dist/commands/payments/payouts.d.ts.map +1 -0
- package/dist/commands/payments/payouts.js +147 -0
- package/dist/commands/payments/payouts.js.map +1 -0
- package/dist/commands/payments/rate.d.ts +48 -0
- package/dist/commands/payments/rate.d.ts.map +1 -0
- package/dist/commands/payments/rate.js +229 -0
- package/dist/commands/payments/rate.js.map +1 -0
- package/dist/commands/payments/shared.d.ts +10 -0
- package/dist/commands/payments/shared.d.ts.map +1 -0
- package/dist/commands/payments/shared.js +27 -0
- package/dist/commands/payments/shared.js.map +1 -0
- package/dist/commands/profile/basic/index.d.ts +18 -0
- package/dist/commands/profile/basic/index.d.ts.map +1 -0
- package/dist/commands/profile/basic/index.js +79 -0
- package/dist/commands/profile/basic/index.js.map +1 -0
- package/dist/commands/profile/basic/photo-show.d.ts +28 -0
- package/dist/commands/profile/basic/photo-show.d.ts.map +1 -0
- package/dist/commands/profile/basic/photo-show.js +112 -0
- package/dist/commands/profile/basic/photo-show.js.map +1 -0
- package/dist/commands/profile/basic/photo-upload.d.ts +10 -0
- package/dist/commands/profile/basic/photo-upload.d.ts.map +1 -0
- package/dist/commands/profile/basic/photo-upload.js +61 -0
- package/dist/commands/profile/basic/photo-upload.js.map +1 -0
- package/dist/commands/profile/basic/set.d.ts +54 -0
- package/dist/commands/profile/basic/set.d.ts.map +1 -0
- package/dist/commands/profile/basic/set.js +174 -0
- package/dist/commands/profile/basic/set.js.map +1 -0
- package/dist/commands/profile/basic/show.d.ts +95 -0
- package/dist/commands/profile/basic/show.d.ts.map +1 -0
- package/dist/commands/profile/basic/show.js +310 -0
- package/dist/commands/profile/basic/show.js.map +1 -0
- package/dist/commands/profile/certifications/index.d.ts +40 -0
- package/dist/commands/profile/certifications/index.d.ts.map +1 -0
- package/dist/commands/profile/certifications/index.js +350 -0
- package/dist/commands/profile/certifications/index.js.map +1 -0
- package/dist/commands/profile/education/index.d.ts +37 -0
- package/dist/commands/profile/education/index.d.ts.map +1 -0
- package/dist/commands/profile/education/index.js +331 -0
- package/dist/commands/profile/education/index.js.map +1 -0
- package/dist/commands/profile/employment/index.d.ts +49 -0
- package/dist/commands/profile/employment/index.d.ts.map +1 -0
- package/dist/commands/profile/employment/index.js +425 -0
- package/dist/commands/profile/employment/index.js.map +1 -0
- package/dist/commands/profile/external/_shared.d.ts +35 -0
- package/dist/commands/profile/external/_shared.d.ts.map +1 -0
- package/dist/commands/profile/external/_shared.js +59 -0
- package/dist/commands/profile/external/_shared.js.map +1 -0
- package/dist/commands/profile/external/advanced-wizard-show.d.ts +15 -0
- package/dist/commands/profile/external/advanced-wizard-show.d.ts.map +1 -0
- package/dist/commands/profile/external/advanced-wizard-show.js +82 -0
- package/dist/commands/profile/external/advanced-wizard-show.js.map +1 -0
- package/dist/commands/profile/external/custom-requirements-set.d.ts +32 -0
- package/dist/commands/profile/external/custom-requirements-set.d.ts.map +1 -0
- package/dist/commands/profile/external/custom-requirements-set.js +116 -0
- package/dist/commands/profile/external/custom-requirements-set.js.map +1 -0
- package/dist/commands/profile/external/custom-requirements-show.d.ts +16 -0
- package/dist/commands/profile/external/custom-requirements-show.d.ts.map +1 -0
- package/dist/commands/profile/external/custom-requirements-show.js +84 -0
- package/dist/commands/profile/external/custom-requirements-show.js.map +1 -0
- package/dist/commands/profile/external/index.d.ts +21 -0
- package/dist/commands/profile/external/index.d.ts.map +1 -0
- package/dist/commands/profile/external/index.js +113 -0
- package/dist/commands/profile/external/index.js.map +1 -0
- package/dist/commands/profile/external/readiness.d.ts +15 -0
- package/dist/commands/profile/external/readiness.d.ts.map +1 -0
- package/dist/commands/profile/external/readiness.js +104 -0
- package/dist/commands/profile/external/readiness.js.map +1 -0
- package/dist/commands/profile/external/recommendations.d.ts +17 -0
- package/dist/commands/profile/external/recommendations.d.ts.map +1 -0
- package/dist/commands/profile/external/recommendations.js +97 -0
- package/dist/commands/profile/external/recommendations.js.map +1 -0
- package/dist/commands/profile/external/show.d.ts +22 -0
- package/dist/commands/profile/external/show.d.ts.map +1 -0
- package/dist/commands/profile/external/show.js +83 -0
- package/dist/commands/profile/external/show.js.map +1 -0
- package/dist/commands/profile/external/update.d.ts +37 -0
- package/dist/commands/profile/external/update.d.ts.map +1 -0
- package/dist/commands/profile/external/update.js +125 -0
- package/dist/commands/profile/external/update.js.map +1 -0
- package/dist/commands/profile/index.d.ts +16 -0
- package/dist/commands/profile/index.d.ts.map +1 -0
- package/dist/commands/profile/index.js +81 -0
- package/dist/commands/profile/index.js.map +1 -0
- package/dist/commands/profile/industries/index.d.ts +43 -0
- package/dist/commands/profile/industries/index.d.ts.map +1 -0
- package/dist/commands/profile/industries/index.js +258 -0
- package/dist/commands/profile/industries/index.js.map +1 -0
- package/dist/commands/profile/portfolio/add.d.ts +43 -0
- package/dist/commands/profile/portfolio/add.d.ts.map +1 -0
- package/dist/commands/profile/portfolio/add.js +181 -0
- package/dist/commands/profile/portfolio/add.js.map +1 -0
- package/dist/commands/profile/portfolio/highlight.d.ts +11 -0
- package/dist/commands/profile/portfolio/highlight.d.ts.map +1 -0
- package/dist/commands/profile/portfolio/highlight.js +31 -0
- package/dist/commands/profile/portfolio/highlight.js.map +1 -0
- package/dist/commands/profile/portfolio/index.d.ts +16 -0
- package/dist/commands/profile/portfolio/index.d.ts.map +1 -0
- package/dist/commands/profile/portfolio/index.js +121 -0
- package/dist/commands/profile/portfolio/index.js.map +1 -0
- package/dist/commands/profile/portfolio/list.d.ts +83 -0
- package/dist/commands/profile/portfolio/list.d.ts.map +1 -0
- package/dist/commands/profile/portfolio/list.js +189 -0
- package/dist/commands/profile/portfolio/list.js.map +1 -0
- package/dist/commands/profile/portfolio/remove.d.ts +9 -0
- package/dist/commands/profile/portfolio/remove.d.ts.map +1 -0
- package/dist/commands/profile/portfolio/remove.js +24 -0
- package/dist/commands/profile/portfolio/remove.js.map +1 -0
- package/dist/commands/profile/portfolio/reorder.d.ts +17 -0
- package/dist/commands/profile/portfolio/reorder.d.ts.map +1 -0
- package/dist/commands/profile/portfolio/reorder.js +135 -0
- package/dist/commands/profile/portfolio/reorder.js.map +1 -0
- package/dist/commands/profile/portfolio/shared.d.ts +8 -0
- package/dist/commands/profile/portfolio/shared.d.ts.map +1 -0
- package/dist/commands/profile/portfolio/shared.js +10 -0
- package/dist/commands/profile/portfolio/shared.js.map +1 -0
- package/dist/commands/profile/portfolio/update.d.ts +18 -0
- package/dist/commands/profile/portfolio/update.d.ts.map +1 -0
- package/dist/commands/profile/portfolio/update.js +77 -0
- package/dist/commands/profile/portfolio/update.js.map +1 -0
- package/dist/commands/profile/portfolio/upload.d.ts +8 -0
- package/dist/commands/profile/portfolio/upload.d.ts.map +1 -0
- package/dist/commands/profile/portfolio/upload.js +131 -0
- package/dist/commands/profile/portfolio/upload.js.map +1 -0
- package/dist/commands/profile/resume/cancel-upload.d.ts +9 -0
- package/dist/commands/profile/resume/cancel-upload.d.ts.map +1 -0
- package/dist/commands/profile/resume/cancel-upload.js +30 -0
- package/dist/commands/profile/resume/cancel-upload.js.map +1 -0
- package/dist/commands/profile/resume/index.d.ts +15 -0
- package/dist/commands/profile/resume/index.d.ts.map +1 -0
- package/dist/commands/profile/resume/index.js +42 -0
- package/dist/commands/profile/resume/index.js.map +1 -0
- package/dist/commands/profile/resume/upload.d.ts +16 -0
- package/dist/commands/profile/resume/upload.d.ts.map +1 -0
- package/dist/commands/profile/resume/upload.js +65 -0
- package/dist/commands/profile/resume/upload.js.map +1 -0
- package/dist/commands/profile/reviews/_shared.d.ts +9 -0
- package/dist/commands/profile/reviews/_shared.d.ts.map +1 -0
- package/dist/commands/profile/reviews/_shared.js +15 -0
- package/dist/commands/profile/reviews/_shared.js.map +1 -0
- package/dist/commands/profile/reviews/approve-item.d.ts +30 -0
- package/dist/commands/profile/reviews/approve-item.d.ts.map +1 -0
- package/dist/commands/profile/reviews/approve-item.js +82 -0
- package/dist/commands/profile/reviews/approve-item.js.map +1 -0
- package/dist/commands/profile/reviews/approve-section.d.ts +15 -0
- package/dist/commands/profile/reviews/approve-section.d.ts.map +1 -0
- package/dist/commands/profile/reviews/approve-section.js +67 -0
- package/dist/commands/profile/reviews/approve-section.js.map +1 -0
- package/dist/commands/profile/reviews/index.d.ts +19 -0
- package/dist/commands/profile/reviews/index.d.ts.map +1 -0
- package/dist/commands/profile/reviews/index.js +71 -0
- package/dist/commands/profile/reviews/index.js.map +1 -0
- package/dist/commands/profile/reviews/list.d.ts +17 -0
- package/dist/commands/profile/reviews/list.d.ts.map +1 -0
- package/dist/commands/profile/reviews/list.js +96 -0
- package/dist/commands/profile/reviews/list.js.map +1 -0
- package/dist/commands/profile/reviews/submit-for-review.d.ts +16 -0
- package/dist/commands/profile/reviews/submit-for-review.d.ts.map +1 -0
- package/dist/commands/profile/reviews/submit-for-review.js +65 -0
- package/dist/commands/profile/reviews/submit-for-review.js.map +1 -0
- package/dist/commands/profile/shared.d.ts +46 -0
- package/dist/commands/profile/shared.d.ts.map +1 -0
- package/dist/commands/profile/shared.js +111 -0
- package/dist/commands/profile/shared.js.map +1 -0
- package/dist/commands/profile/skills/index.d.ts +29 -0
- package/dist/commands/profile/skills/index.d.ts.map +1 -0
- package/dist/commands/profile/skills/index.js +475 -0
- package/dist/commands/profile/skills/index.js.map +1 -0
- package/dist/commands/profile/visas/add.d.ts +19 -0
- package/dist/commands/profile/visas/add.d.ts.map +1 -0
- package/dist/commands/profile/visas/add.js +37 -0
- package/dist/commands/profile/visas/add.js.map +1 -0
- package/dist/commands/profile/visas/index.d.ts +13 -0
- package/dist/commands/profile/visas/index.d.ts.map +1 -0
- package/dist/commands/profile/visas/index.js +69 -0
- package/dist/commands/profile/visas/index.js.map +1 -0
- package/dist/commands/profile/visas/list.d.ts +40 -0
- package/dist/commands/profile/visas/list.d.ts.map +1 -0
- package/dist/commands/profile/visas/list.js +115 -0
- package/dist/commands/profile/visas/list.js.map +1 -0
- package/dist/commands/profile/visas/remove.d.ts +8 -0
- package/dist/commands/profile/visas/remove.d.ts.map +1 -0
- package/dist/commands/profile/visas/remove.js +23 -0
- package/dist/commands/profile/visas/remove.js.map +1 -0
- package/dist/commands/profile/visas/shared.d.ts +11 -0
- package/dist/commands/profile/visas/shared.d.ts.map +1 -0
- package/dist/commands/profile/visas/shared.js +16 -0
- package/dist/commands/profile/visas/shared.js.map +1 -0
- package/dist/commands/profile/visas/update.d.ts +13 -0
- package/dist/commands/profile/visas/update.d.ts.map +1 -0
- package/dist/commands/profile/visas/update.js +44 -0
- package/dist/commands/profile/visas/update.js.map +1 -0
- package/dist/commands/timesheet/index.d.ts +24 -0
- package/dist/commands/timesheet/index.d.ts.map +1 -0
- package/dist/commands/timesheet/index.js +98 -0
- package/dist/commands/timesheet/index.js.map +1 -0
- package/dist/commands/timesheet/list.d.ts +40 -0
- package/dist/commands/timesheet/list.d.ts.map +1 -0
- package/dist/commands/timesheet/list.js +79 -0
- package/dist/commands/timesheet/list.js.map +1 -0
- package/dist/commands/timesheet/shared.d.ts +10 -0
- package/dist/commands/timesheet/shared.d.ts.map +1 -0
- package/dist/commands/timesheet/shared.js +35 -0
- package/dist/commands/timesheet/shared.js.map +1 -0
- package/dist/commands/timesheet/show.d.ts +19 -0
- package/dist/commands/timesheet/show.d.ts.map +1 -0
- package/dist/commands/timesheet/show.js +109 -0
- package/dist/commands/timesheet/show.js.map +1 -0
- package/dist/commands/timesheet/submit.d.ts +50 -0
- package/dist/commands/timesheet/submit.d.ts.map +1 -0
- package/dist/commands/timesheet/submit.js +151 -0
- package/dist/commands/timesheet/submit.js.map +1 -0
- package/dist/crash-handlers.d.ts +67 -0
- package/dist/crash-handlers.d.ts.map +1 -0
- package/dist/crash-handlers.js +78 -0
- package/dist/crash-handlers.js.map +1 -0
- package/dist/errors.d.ts +45 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +57 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +8 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/config-context.d.ts +41 -0
- package/dist/lib/config-context.d.ts.map +1 -0
- package/dist/lib/config-context.js +74 -0
- package/dist/lib/config-context.js.map +1 -0
- package/dist/lib/dry-run.d.ts +70 -0
- package/dist/lib/dry-run.d.ts.map +1 -0
- package/dist/lib/dry-run.js +114 -0
- package/dist/lib/dry-run.js.map +1 -0
- package/dist/lib/empty-state-cta.d.ts +63 -0
- package/dist/lib/empty-state-cta.d.ts.map +1 -0
- package/dist/lib/empty-state-cta.js +88 -0
- package/dist/lib/empty-state-cta.js.map +1 -0
- package/dist/lib/envelopes.d.ts +540 -0
- package/dist/lib/envelopes.d.ts.map +1 -0
- package/dist/lib/envelopes.js +598 -0
- package/dist/lib/envelopes.js.map +1 -0
- package/dist/lib/error-routing.d.ts +49 -0
- package/dist/lib/error-routing.d.ts.map +1 -0
- package/dist/lib/error-routing.js +72 -0
- package/dist/lib/error-routing.js.map +1 -0
- package/dist/lib/format-helpers.d.ts +65 -0
- package/dist/lib/format-helpers.d.ts.map +1 -0
- package/dist/lib/format-helpers.js +79 -0
- package/dist/lib/format-helpers.js.map +1 -0
- package/dist/lib/format-overrides.d.ts +81 -0
- package/dist/lib/format-overrides.d.ts.map +1 -0
- package/dist/lib/format-overrides.js +55 -0
- package/dist/lib/format-overrides.js.map +1 -0
- package/dist/lib/freetext.d.ts +83 -0
- package/dist/lib/freetext.d.ts.map +1 -0
- package/dist/lib/freetext.js +182 -0
- package/dist/lib/freetext.js.map +1 -0
- package/dist/lib/kill-switch-hook.d.ts +49 -0
- package/dist/lib/kill-switch-hook.d.ts.map +1 -0
- package/dist/lib/kill-switch-hook.js +34 -0
- package/dist/lib/kill-switch-hook.js.map +1 -0
- package/dist/lib/output.d.ts +173 -0
- package/dist/lib/output.d.ts.map +1 -0
- package/dist/lib/output.js +177 -0
- package/dist/lib/output.js.map +1 -0
- package/dist/lib/pagination.d.ts +49 -0
- package/dist/lib/pagination.d.ts.map +1 -0
- package/dist/lib/pagination.js +36 -0
- package/dist/lib/pagination.js.map +1 -0
- package/dist/program.d.ts +80 -0
- package/dist/program.d.ts.map +1 -0
- package/dist/program.js +273 -0
- package/dist/program.js.map +1 -0
- package/package.json +35 -13
- package/index.js +0 -7
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { TtctlError } from "@ttctl/core";
|
|
4
|
+
import { exitCodeForTtctlError, presentTtctlError } from "../errors.js";
|
|
5
|
+
import { emitErrorAndExit } from "./envelopes.js";
|
|
6
|
+
/**
|
|
7
|
+
* Generic CLI error router (#330). Single source of truth for the
|
|
8
|
+
* branching logic that was previously copied into nine structurally
|
|
9
|
+
* identical handler functions across `packages/cli/src/commands/*\/shared.ts`
|
|
10
|
+
* (one per sub-domain). Each domain re-exports a thin wrapper that
|
|
11
|
+
* closes over its `DomainErrorClass` (and optionally a per-code hint
|
|
12
|
+
* adapter) so the call sites in action handlers stay unchanged.
|
|
13
|
+
*
|
|
14
|
+
* Three branches in priority order:
|
|
15
|
+
*
|
|
16
|
+
* 1. `TtctlError` subclasses (`AuthRevokedError`, `Cf403Error`,
|
|
17
|
+
* `Cf403PersistentError`, `SchedulerBearerExpired`, …) keep their
|
|
18
|
+
* dedicated 3-block pretty rendering on `pretty` (Error / Recovery /
|
|
19
|
+
* Code) via {@link presentTtctlError}; `json` / `yaml` flow through
|
|
20
|
+
* the envelope so machine consumers see the stable wire shape. Exit
|
|
21
|
+
* code routes via {@link exitCodeForTtctlError} — Cloudflare-403
|
|
22
|
+
* codes exit `2`, everything else `1`.
|
|
23
|
+
* 2. Domain errors (i.e. `instanceof DomainErrorClass`) flow through the
|
|
24
|
+
* envelope. When `hintForCode` is supplied and returns a string for
|
|
25
|
+
* the given code, the envelope entry carries a `hint:` field;
|
|
26
|
+
* otherwise the entry is just `{code, message}`.
|
|
27
|
+
* `exactOptionalPropertyTypes: true` — the entry is built additively
|
|
28
|
+
* so the omitted-vs-undefined distinction is preserved at the
|
|
29
|
+
* envelope boundary.
|
|
30
|
+
* 3. Anything else (a plain `Error` thrown from helper code, or a
|
|
31
|
+
* non-Error throw) collapses into `INTERNAL_ERROR` so the user sees
|
|
32
|
+
* a structured envelope rather than the bare exception message.
|
|
33
|
+
*
|
|
34
|
+
* `commandLabel` is the user-visible prefix (e.g. `"applications show"`);
|
|
35
|
+
* the envelope `operation` is derived by replacing spaces with dots
|
|
36
|
+
* (`"applications.show"`).
|
|
37
|
+
*
|
|
38
|
+
* Returns `never` — every branch exits the process via `process.exit`.
|
|
39
|
+
*/
|
|
40
|
+
export function handleDomainError(commandLabel, err, DomainErrorClass, format = "pretty", hintForCode) {
|
|
41
|
+
const operation = commandLabel.replace(/ /g, ".");
|
|
42
|
+
if (err instanceof TtctlError) {
|
|
43
|
+
if (format === "pretty")
|
|
44
|
+
presentTtctlError(err);
|
|
45
|
+
emitErrorAndExit({
|
|
46
|
+
operation,
|
|
47
|
+
format,
|
|
48
|
+
errors: [{ code: err.code, message: err.message, hint: err.recovery }],
|
|
49
|
+
exitCode: exitCodeForTtctlError(err),
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
if (err instanceof DomainErrorClass) {
|
|
53
|
+
const envelopeError = { code: err.code, message: err.message };
|
|
54
|
+
const hint = hintForCode?.(err.code);
|
|
55
|
+
if (hint !== undefined)
|
|
56
|
+
envelopeError.hint = hint;
|
|
57
|
+
emitErrorAndExit({
|
|
58
|
+
operation,
|
|
59
|
+
format,
|
|
60
|
+
errors: [envelopeError],
|
|
61
|
+
prettySummary: `${commandLabel} failed (${err.code}): ${err.message}`,
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
65
|
+
emitErrorAndExit({
|
|
66
|
+
operation,
|
|
67
|
+
format,
|
|
68
|
+
errors: [{ code: "INTERNAL_ERROR", message }],
|
|
69
|
+
prettySummary: `${commandLabel} failed: ${message}`,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=error-routing.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-routing.js","sourceRoot":"","sources":["../../src/lib/error-routing.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,EAAE,qBAAqB,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AACxE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAiBlD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,UAAU,iBAAiB,CAC/B,YAAoB,EACpB,GAAY,EACZ,gBAA6C,EAC7C,SAAuB,QAAQ,EAC/B,WAAqD;IAErD,MAAM,SAAS,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAClD,IAAI,GAAG,YAAY,UAAU,EAAE,CAAC;QAC9B,IAAI,MAAM,KAAK,QAAQ;YAAE,iBAAiB,CAAC,GAAG,CAAC,CAAC;QAChD,gBAAgB,CAAC;YACf,SAAS;YACT,MAAM;YACN,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,IAAI,EAAE,GAAG,CAAC,QAAQ,EAAE,CAAC;YACtE,QAAQ,EAAE,qBAAqB,CAAC,GAAG,CAAC;SACrC,CAAC,CAAC;IACL,CAAC;IACD,IAAI,GAAG,YAAY,gBAAgB,EAAE,CAAC;QACpC,MAAM,aAAa,GAAkB,EAAE,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,CAAC;QAC9E,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACrC,IAAI,IAAI,KAAK,SAAS;YAAE,aAAa,CAAC,IAAI,GAAG,IAAI,CAAC;QAClD,gBAAgB,CAAC;YACf,SAAS;YACT,MAAM;YACN,MAAM,EAAE,CAAC,aAAa,CAAC;YACvB,aAAa,EAAE,GAAG,YAAY,YAAY,GAAG,CAAC,IAAI,MAAM,GAAG,CAAC,OAAO,EAAE;SACtE,CAAC,CAAC;IACL,CAAC;IACD,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjE,gBAAgB,CAAC;QACf,SAAS;QACT,MAAM;QACN,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,gBAAgB,EAAE,OAAO,EAAE,CAAC;QAC7C,aAAa,EAAE,GAAG,YAAY,YAAY,OAAO,EAAE;KACpD,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared rendering helpers for the post-#126 `pretty` format. Centralised
|
|
3
|
+
* so every sub-domain formatter applies the same null convention and
|
|
4
|
+
* paragraph layout — the audit at
|
|
5
|
+
* `docs/audit/2026-05-output-format-formatter-audit.md` flagged at least
|
|
6
|
+
* four distinct null-rendering conventions across the 11 sub-domains.
|
|
7
|
+
*
|
|
8
|
+
* Used today by the rewritten `formatProfilePretty` (basic) and
|
|
9
|
+
* `formatPortfolioPretty` (portfolio) per #129. Other sub-domains adopt
|
|
10
|
+
* these helpers as their formatters are revisited.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Default placeholder for fields the user CAN set but hasn't. Renders
|
|
14
|
+
* verbatim in `pretty` per the audit's standardisation recommendation
|
|
15
|
+
* (§ Standardization Recommendation for `pretty`). The placeholder is
|
|
16
|
+
* intentionally bracketed so it cannot collide with a value the user
|
|
17
|
+
* stored — `(` / `)` are not valid leading characters in any of the
|
|
18
|
+
* Toptal profile fields we render.
|
|
19
|
+
*/
|
|
20
|
+
export declare const UNSET_PLACEHOLDER = "(unset)";
|
|
21
|
+
/**
|
|
22
|
+
* Coerce a `string | null | undefined | ""` value into either the value
|
|
23
|
+
* itself (when present) or a placeholder. The empty string is treated as
|
|
24
|
+
* "unset" because the talent-profile API returns `""` for fields the
|
|
25
|
+
* user has explicitly cleared (e.g., a deleted bio surfaces as
|
|
26
|
+
* `about: ""`, not `about: null`) — empirically observed in the
|
|
27
|
+
* `UPDATE_BASIC_INFO` round-trip and the `Profile.city` server contract.
|
|
28
|
+
*
|
|
29
|
+
* Pass an explicit `fallback` when the formatter wants a CTA-style
|
|
30
|
+
* placeholder (e.g., `"(unset — set with: ttctl profile basic update --bio
|
|
31
|
+
* \"<text>\")"`); the default `"(unset)"` is the audit-standardised
|
|
32
|
+
* convention.
|
|
33
|
+
*/
|
|
34
|
+
export declare function unsetOr(value: string | null | undefined, fallback?: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Indent every line of `text` by `indent` (default: two spaces). Empty
|
|
37
|
+
* lines stay empty so paragraph breaks survive verbatim — the audit's
|
|
38
|
+
* `pretty` contract requires `\n\n` in a source field to render as
|
|
39
|
+
* actual blank lines, not escaped strings.
|
|
40
|
+
*
|
|
41
|
+
* Caller-controlled indent string lets a formatter compose nested
|
|
42
|
+
* indentation (e.g., a portfolio item already indented two spaces from
|
|
43
|
+
* the list marker can pass `" "` to indent its description body four
|
|
44
|
+
* spaces total).
|
|
45
|
+
*/
|
|
46
|
+
export declare function indentLines(text: string, indent?: string): string;
|
|
47
|
+
/**
|
|
48
|
+
* Render a multi-paragraph field for `pretty` output: emit the prefix on
|
|
49
|
+
* its own line, then the body indented one level deeper. Paragraph breaks
|
|
50
|
+
* (`\n\n` in source) survive as actual blank lines via {@link indentLines}.
|
|
51
|
+
*
|
|
52
|
+
* The two-line shape ("Header:" then indented body) matches the audit's
|
|
53
|
+
* recommendation for paragraph-bearing fields — single-line prefixes
|
|
54
|
+
* collapse hierarchy and force the user to scan past the prefix to find
|
|
55
|
+
* the start of the value.
|
|
56
|
+
*
|
|
57
|
+
* `outerIndent` is the indent of the prefix line itself (the surrounding
|
|
58
|
+
* formatter's indent level); the body is indented `outerIndent + " "`.
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* renderMultiParagraph("Bio", "Hello.\n\nWorld.", " ")
|
|
62
|
+
* // " Bio:\n Hello.\n\n World."
|
|
63
|
+
*/
|
|
64
|
+
export declare function renderMultiParagraph(prefix: string, body: string, outerIndent?: string): string;
|
|
65
|
+
//# sourceMappingURL=format-helpers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-helpers.d.ts","sourceRoot":"","sources":["../../src/lib/format-helpers.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;GAUG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,iBAAiB,YAAY,CAAC;AAE3C;;;;;;;;;;;;GAYG;AACH,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EAAE,QAAQ,GAAE,MAA0B,GAAG,MAAM,CAGtG;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,MAAa,GAAG,MAAM,CAKvE;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,WAAW,GAAE,MAAa,GAAG,MAAM,CAGrG"}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
/**
|
|
4
|
+
* Shared rendering helpers for the post-#126 `pretty` format. Centralised
|
|
5
|
+
* so every sub-domain formatter applies the same null convention and
|
|
6
|
+
* paragraph layout — the audit at
|
|
7
|
+
* `docs/audit/2026-05-output-format-formatter-audit.md` flagged at least
|
|
8
|
+
* four distinct null-rendering conventions across the 11 sub-domains.
|
|
9
|
+
*
|
|
10
|
+
* Used today by the rewritten `formatProfilePretty` (basic) and
|
|
11
|
+
* `formatPortfolioPretty` (portfolio) per #129. Other sub-domains adopt
|
|
12
|
+
* these helpers as their formatters are revisited.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Default placeholder for fields the user CAN set but hasn't. Renders
|
|
16
|
+
* verbatim in `pretty` per the audit's standardisation recommendation
|
|
17
|
+
* (§ Standardization Recommendation for `pretty`). The placeholder is
|
|
18
|
+
* intentionally bracketed so it cannot collide with a value the user
|
|
19
|
+
* stored — `(` / `)` are not valid leading characters in any of the
|
|
20
|
+
* Toptal profile fields we render.
|
|
21
|
+
*/
|
|
22
|
+
export const UNSET_PLACEHOLDER = "(unset)";
|
|
23
|
+
/**
|
|
24
|
+
* Coerce a `string | null | undefined | ""` value into either the value
|
|
25
|
+
* itself (when present) or a placeholder. The empty string is treated as
|
|
26
|
+
* "unset" because the talent-profile API returns `""` for fields the
|
|
27
|
+
* user has explicitly cleared (e.g., a deleted bio surfaces as
|
|
28
|
+
* `about: ""`, not `about: null`) — empirically observed in the
|
|
29
|
+
* `UPDATE_BASIC_INFO` round-trip and the `Profile.city` server contract.
|
|
30
|
+
*
|
|
31
|
+
* Pass an explicit `fallback` when the formatter wants a CTA-style
|
|
32
|
+
* placeholder (e.g., `"(unset — set with: ttctl profile basic update --bio
|
|
33
|
+
* \"<text>\")"`); the default `"(unset)"` is the audit-standardised
|
|
34
|
+
* convention.
|
|
35
|
+
*/
|
|
36
|
+
export function unsetOr(value, fallback = UNSET_PLACEHOLDER) {
|
|
37
|
+
if (value === null || value === undefined || value === "")
|
|
38
|
+
return fallback;
|
|
39
|
+
return value;
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Indent every line of `text` by `indent` (default: two spaces). Empty
|
|
43
|
+
* lines stay empty so paragraph breaks survive verbatim — the audit's
|
|
44
|
+
* `pretty` contract requires `\n\n` in a source field to render as
|
|
45
|
+
* actual blank lines, not escaped strings.
|
|
46
|
+
*
|
|
47
|
+
* Caller-controlled indent string lets a formatter compose nested
|
|
48
|
+
* indentation (e.g., a portfolio item already indented two spaces from
|
|
49
|
+
* the list marker can pass `" "` to indent its description body four
|
|
50
|
+
* spaces total).
|
|
51
|
+
*/
|
|
52
|
+
export function indentLines(text, indent = " ") {
|
|
53
|
+
return text
|
|
54
|
+
.split("\n")
|
|
55
|
+
.map((line) => (line === "" ? "" : `${indent}${line}`))
|
|
56
|
+
.join("\n");
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Render a multi-paragraph field for `pretty` output: emit the prefix on
|
|
60
|
+
* its own line, then the body indented one level deeper. Paragraph breaks
|
|
61
|
+
* (`\n\n` in source) survive as actual blank lines via {@link indentLines}.
|
|
62
|
+
*
|
|
63
|
+
* The two-line shape ("Header:" then indented body) matches the audit's
|
|
64
|
+
* recommendation for paragraph-bearing fields — single-line prefixes
|
|
65
|
+
* collapse hierarchy and force the user to scan past the prefix to find
|
|
66
|
+
* the start of the value.
|
|
67
|
+
*
|
|
68
|
+
* `outerIndent` is the indent of the prefix line itself (the surrounding
|
|
69
|
+
* formatter's indent level); the body is indented `outerIndent + " "`.
|
|
70
|
+
*
|
|
71
|
+
* @example
|
|
72
|
+
* renderMultiParagraph("Bio", "Hello.\n\nWorld.", " ")
|
|
73
|
+
* // " Bio:\n Hello.\n\n World."
|
|
74
|
+
*/
|
|
75
|
+
export function renderMultiParagraph(prefix, body, outerIndent = " ") {
|
|
76
|
+
const innerIndent = `${outerIndent} `;
|
|
77
|
+
return `${outerIndent}${prefix}:\n${indentLines(body, innerIndent)}`;
|
|
78
|
+
}
|
|
79
|
+
//# sourceMappingURL=format-helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-helpers.js","sourceRoot":"","sources":["../../src/lib/format-helpers.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC;;;;;;;;;;GAUG;AAEH;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,SAAS,CAAC;AAE3C;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,OAAO,CAAC,KAAgC,EAAE,WAAmB,iBAAiB;IAC5F,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE;QAAE,OAAO,QAAQ,CAAC;IAC3E,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,WAAW,CAAC,IAAY,EAAE,SAAiB,IAAI;IAC7D,OAAO,IAAI;SACR,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,MAAM,GAAG,IAAI,EAAE,CAAC,CAAC;SACtD,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAAc,EAAE,IAAY,EAAE,cAAsB,IAAI;IAC3F,MAAM,WAAW,GAAG,GAAG,WAAW,IAAI,CAAC;IACvC,OAAO,GAAG,WAAW,GAAG,MAAM,MAAM,WAAW,CAAC,IAAI,EAAE,WAAW,CAAC,EAAE,CAAC;AACvE,CAAC"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-command output-strategy overrides for the post-reframe `pretty`
|
|
3
|
+
* format dispatch (#121 epic, audit at
|
|
4
|
+
* `docs/audit/2026-05-output-format-formatter-audit.md`).
|
|
5
|
+
*
|
|
6
|
+
* The default `pretty` strategy is `"default"` — one row per
|
|
7
|
+
* field, key/value layout. Some commands carry paragraph-length
|
|
8
|
+
* fields that don't fit a row layout (reviewer comments, portfolio
|
|
9
|
+
* descriptions, employment experience items). Those commands register
|
|
10
|
+
* a `"multi-line"` strategy so the dispatch pipeline routes them to
|
|
11
|
+
* the curated multi-line renderer instead.
|
|
12
|
+
*
|
|
13
|
+
* The registry is keyed by the **canonical command path** —
|
|
14
|
+
* sub-domain verbs only, no Commander.js aliases. Aliases (`certs`
|
|
15
|
+
* for `certifications`, `experience` for `employment`, `rm` for
|
|
16
|
+
* `remove`) MUST collapse to the canonical form before lookup. The
|
|
17
|
+
* dispatch layer (added in a downstream issue) is responsible for
|
|
18
|
+
* the alias collapse.
|
|
19
|
+
*
|
|
20
|
+
* The registry intentionally ships small. Adding an entry should be
|
|
21
|
+
* a deliberate decision tied to a specific defect (e.g., an audit
|
|
22
|
+
* row in the triage report) — not a forward-looking guess.
|
|
23
|
+
*/
|
|
24
|
+
/**
|
|
25
|
+
* Output strategy alternatives the `pretty` dispatcher can select.
|
|
26
|
+
*
|
|
27
|
+
* - `"default"` — fall through to the per-command formatter
|
|
28
|
+
* registered alongside the action handler. The dispatcher does not
|
|
29
|
+
* intervene.
|
|
30
|
+
* - `"multi-line"` — route through the curated multi-line renderer.
|
|
31
|
+
* Used for commands whose entity carries paragraph-length text that
|
|
32
|
+
* would overflow a row-based layout.
|
|
33
|
+
*
|
|
34
|
+
* Future strategies (e.g., `"compact"` for inline single-line lists)
|
|
35
|
+
* land as additional union members.
|
|
36
|
+
*/
|
|
37
|
+
export type FormatStrategy = "default" | "multi-line";
|
|
38
|
+
/**
|
|
39
|
+
* Per-command-path strategy registry. Lookup is by canonical command
|
|
40
|
+
* path (e.g., `"profile reviews list"`). Unknown paths fall through
|
|
41
|
+
* to {@link DEFAULT_STRATEGY}.
|
|
42
|
+
*
|
|
43
|
+
* The registry is `ReadonlyMap` to discourage mutation at the call
|
|
44
|
+
* site; tests that need to override entries should construct a fresh
|
|
45
|
+
* map and pass it through a dependency-injected lookup function (the
|
|
46
|
+
* registry is not a global singleton in spirit — `resolveStrategy`
|
|
47
|
+
* accepts an explicit map for testability).
|
|
48
|
+
*
|
|
49
|
+
* Initial entries (per § Override Registry Decisions in the audit):
|
|
50
|
+
*
|
|
51
|
+
* - `profile reviews list`: forward-looking. The current entity
|
|
52
|
+
* (`SectionReview`) carries no paragraph-length fields, but #127
|
|
53
|
+
* may surface reviewer-comment / rejection-reason fields, at which
|
|
54
|
+
* point a row-based table breaks. Registering today is no-cost
|
|
55
|
+
* (multi-line still reads fine on short data) and forward-safe.
|
|
56
|
+
*
|
|
57
|
+
* Two further candidates are tracked as TODO comments below for the
|
|
58
|
+
* downstream issue (#129 — formatter rewrites) to enroll once their
|
|
59
|
+
* formatters are reshaped:
|
|
60
|
+
*
|
|
61
|
+
* - `profile employment list`: `experienceItems` is paragraph-length
|
|
62
|
+
* today; current table renders only a count.
|
|
63
|
+
* - `profile portfolio list`: `description` and `accomplishment` are
|
|
64
|
+
* paragraph-length post-#129 fix.
|
|
65
|
+
*/
|
|
66
|
+
export declare const FORMAT_OVERRIDES: ReadonlyMap<string, FormatStrategy>;
|
|
67
|
+
/**
|
|
68
|
+
* Default strategy when a command path has no registered override.
|
|
69
|
+
* Exported so callers and tests can reference the same constant.
|
|
70
|
+
*/
|
|
71
|
+
export declare const DEFAULT_STRATEGY: FormatStrategy;
|
|
72
|
+
/**
|
|
73
|
+
* Resolve the format strategy for a canonical command path. Pure —
|
|
74
|
+
* no I/O. The optional `overrides` parameter lets tests inject an
|
|
75
|
+
* alternate registry without touching the module-level constant.
|
|
76
|
+
*
|
|
77
|
+
* Lookup is case-sensitive and exact-match. Aliases must collapse to
|
|
78
|
+
* the canonical form upstream.
|
|
79
|
+
*/
|
|
80
|
+
export declare function resolveStrategy(commandPath: string, overrides?: ReadonlyMap<string, FormatStrategy>): FormatStrategy;
|
|
81
|
+
//# sourceMappingURL=format-overrides.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-overrides.d.ts","sourceRoot":"","sources":["../../src/lib/format-overrides.ts"],"names":[],"mappings":"AAGA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,cAAc,GAAG,SAAS,GAAG,YAAY,CAAC;AAEtD;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAO/D,CAAC;AAEH;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,cAA0B,CAAC;AAE1D;;;;;;;GAOG;AACH,wBAAgB,eAAe,CAC7B,WAAW,EAAE,MAAM,EACnB,SAAS,GAAE,WAAW,CAAC,MAAM,EAAE,cAAc,CAAoB,GAChE,cAAc,CAEhB"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
/**
|
|
4
|
+
* Per-command-path strategy registry. Lookup is by canonical command
|
|
5
|
+
* path (e.g., `"profile reviews list"`). Unknown paths fall through
|
|
6
|
+
* to {@link DEFAULT_STRATEGY}.
|
|
7
|
+
*
|
|
8
|
+
* The registry is `ReadonlyMap` to discourage mutation at the call
|
|
9
|
+
* site; tests that need to override entries should construct a fresh
|
|
10
|
+
* map and pass it through a dependency-injected lookup function (the
|
|
11
|
+
* registry is not a global singleton in spirit — `resolveStrategy`
|
|
12
|
+
* accepts an explicit map for testability).
|
|
13
|
+
*
|
|
14
|
+
* Initial entries (per § Override Registry Decisions in the audit):
|
|
15
|
+
*
|
|
16
|
+
* - `profile reviews list`: forward-looking. The current entity
|
|
17
|
+
* (`SectionReview`) carries no paragraph-length fields, but #127
|
|
18
|
+
* may surface reviewer-comment / rejection-reason fields, at which
|
|
19
|
+
* point a row-based table breaks. Registering today is no-cost
|
|
20
|
+
* (multi-line still reads fine on short data) and forward-safe.
|
|
21
|
+
*
|
|
22
|
+
* Two further candidates are tracked as TODO comments below for the
|
|
23
|
+
* downstream issue (#129 — formatter rewrites) to enroll once their
|
|
24
|
+
* formatters are reshaped:
|
|
25
|
+
*
|
|
26
|
+
* - `profile employment list`: `experienceItems` is paragraph-length
|
|
27
|
+
* today; current table renders only a count.
|
|
28
|
+
* - `profile portfolio list`: `description` and `accomplishment` are
|
|
29
|
+
* paragraph-length post-#129 fix.
|
|
30
|
+
*/
|
|
31
|
+
export const FORMAT_OVERRIDES = new Map([
|
|
32
|
+
["profile reviews list", "multi-line"],
|
|
33
|
+
// TODO(#129): enroll "profile employment list" → "multi-line" once
|
|
34
|
+
// the formatter is rewritten to render `experienceItems` content.
|
|
35
|
+
// TODO(#129): enroll "profile portfolio list" → "multi-line" once
|
|
36
|
+
// the formatter is rewritten to render `description` and
|
|
37
|
+
// `accomplishment`.
|
|
38
|
+
]);
|
|
39
|
+
/**
|
|
40
|
+
* Default strategy when a command path has no registered override.
|
|
41
|
+
* Exported so callers and tests can reference the same constant.
|
|
42
|
+
*/
|
|
43
|
+
export const DEFAULT_STRATEGY = "default";
|
|
44
|
+
/**
|
|
45
|
+
* Resolve the format strategy for a canonical command path. Pure —
|
|
46
|
+
* no I/O. The optional `overrides` parameter lets tests inject an
|
|
47
|
+
* alternate registry without touching the module-level constant.
|
|
48
|
+
*
|
|
49
|
+
* Lookup is case-sensitive and exact-match. Aliases must collapse to
|
|
50
|
+
* the canonical form upstream.
|
|
51
|
+
*/
|
|
52
|
+
export function resolveStrategy(commandPath, overrides = FORMAT_OVERRIDES) {
|
|
53
|
+
return overrides.get(commandPath) ?? DEFAULT_STRATEGY;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=format-overrides.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-overrides.js","sourceRoot":"","sources":["../../src/lib/format-overrides.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAyCpC;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAwC,IAAI,GAAG,CAAyB;IACnG,CAAC,sBAAsB,EAAE,YAAY,CAAC;IACtC,mEAAmE;IACnE,kEAAkE;IAClE,kEAAkE;IAClE,yDAAyD;IACzD,oBAAoB;CACrB,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAmB,SAAS,CAAC;AAE1D;;;;;;;GAOG;AACH,MAAM,UAAU,eAAe,CAC7B,WAAmB,EACnB,YAAiD,gBAAgB;IAEjE,OAAO,SAAS,CAAC,GAAG,CAAC,WAAW,CAAC,IAAI,gBAAgB,CAAC;AACxD,CAAC"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { spawn as defaultSpawn } from "node:child_process";
|
|
2
|
+
/**
|
|
3
|
+
* Stable error codes carried by {@link FreeTextError}. Script consumers
|
|
4
|
+
* branch on `error.code` rather than parsing the user-facing prose. Codes
|
|
5
|
+
* intentionally cover only conditions surfaced *before* the helper hands
|
|
6
|
+
* control back to the caller — anything caused by the underlying value
|
|
7
|
+
* (e.g. server-side rejection of an empty bio) is the caller's domain.
|
|
8
|
+
*/
|
|
9
|
+
export type FreeTextErrorCode = "MODE_CONFLICT" | "FILE_NOT_FOUND" | "FILE_READ_ERROR" | "STDIN_UNAVAILABLE" | "STDIN_DOUBLE_CLAIM" | "EDITOR_FAILED";
|
|
10
|
+
/**
|
|
11
|
+
* Typed error thrown by {@link resolveFreeText} for input mistakes the user
|
|
12
|
+
* must fix before retrying. Callers render the standard
|
|
13
|
+
* `<command> failed (<code>): <message>` shape and exit non-zero.
|
|
14
|
+
*
|
|
15
|
+
* Production failures from the API or the platform stay typed as their
|
|
16
|
+
* domain errors (e.g. `profile.basic.ProfileError`, `TtctlError`); this
|
|
17
|
+
* type covers ONLY input-resolution failures that happen on the local
|
|
18
|
+
* machine before any network call.
|
|
19
|
+
*/
|
|
20
|
+
export declare class FreeTextError extends Error {
|
|
21
|
+
readonly code: FreeTextErrorCode;
|
|
22
|
+
readonly name = "FreeTextError";
|
|
23
|
+
constructor(code: FreeTextErrorCode, message: string);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Options for {@link resolveFreeText}. The first block tunes behavior; the
|
|
27
|
+
* trailing block (`stdin` / `readFile` / `spawn`) is the test-injection
|
|
28
|
+
* surface — production callers leave these `undefined` and the helper
|
|
29
|
+
* resolves defaults (`process.stdin`, `node:fs/promises`'s `readFile`,
|
|
30
|
+
* `node:child_process`'s `spawn`).
|
|
31
|
+
*/
|
|
32
|
+
export interface ResolveFreeTextOptions {
|
|
33
|
+
/** User-facing flag name used in error messages, e.g. `"bio"`. */
|
|
34
|
+
readonly flagName: string;
|
|
35
|
+
/** Initial editor buffer for `--edit` mode. Empty string when omitted. */
|
|
36
|
+
readonly currentValue?: string;
|
|
37
|
+
/** Whether the caller's `--edit`-style boolean flag was set. */
|
|
38
|
+
readonly enableEditor?: boolean;
|
|
39
|
+
/** Override the `$EDITOR` lookup. Falls back to `process.env.EDITOR ?? "vi"`. */
|
|
40
|
+
readonly editorEnv?: string;
|
|
41
|
+
/** Test-only: stream consumed for the `-` (stdin) mode. */
|
|
42
|
+
readonly stdin?: NodeJS.ReadableStream;
|
|
43
|
+
/** Test-only: replace the `fs.readFile` used by the `@path` mode. */
|
|
44
|
+
readonly readFile?: (path: string) => Promise<string>;
|
|
45
|
+
/** Test-only: replace `child_process.spawn` used by the editor mode. */
|
|
46
|
+
readonly spawn?: typeof defaultSpawn;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Reset the module-level stdin-claim guard. Test-only. Production callers
|
|
50
|
+
* must not call this — the guard exists precisely to prevent the same
|
|
51
|
+
* process from consuming stdin twice in a single CLI invocation.
|
|
52
|
+
*
|
|
53
|
+
* @internal
|
|
54
|
+
*/
|
|
55
|
+
export declare function _resetStdinClaimForTesting(): void;
|
|
56
|
+
/**
|
|
57
|
+
* Resolve a free-text flag value through the four supported input modes.
|
|
58
|
+
*
|
|
59
|
+
* Modes (in priority order):
|
|
60
|
+
*
|
|
61
|
+
* 1. **Editor** — `enableEditor === true` opens `$EDITOR` seeded with
|
|
62
|
+
* `currentValue` and returns the saved buffer. Combining `enableEditor`
|
|
63
|
+
* with a defined `rawValue` is ambiguous; the helper rejects it before
|
|
64
|
+
* any I/O.
|
|
65
|
+
* 2. **Stdin** — `rawValue === "-"` reads `process.stdin` (or the injected
|
|
66
|
+
* stream) until EOF. Empty stdin is NOT an error — it returns the empty
|
|
67
|
+
* string, per AC. A non-piped TTY surfaces `STDIN_UNAVAILABLE` rather
|
|
68
|
+
* than hanging the CLI forever waiting on an interactive user.
|
|
69
|
+
* 3. **File** — `rawValue.startsWith("@")` reads the file at the path that
|
|
70
|
+
* follows the `@` and returns its UTF-8 contents. ENOENT becomes
|
|
71
|
+
* `FILE_NOT_FOUND`; any other read failure becomes `FILE_READ_ERROR`.
|
|
72
|
+
* 4. **Inline** — any other defined `rawValue` is returned verbatim.
|
|
73
|
+
*
|
|
74
|
+
* Returns `undefined` when neither `rawValue` is defined nor `enableEditor`
|
|
75
|
+
* is set — this is the "user did not pass the flag" case, which the caller
|
|
76
|
+
* usually branches on to leave the field unchanged.
|
|
77
|
+
*
|
|
78
|
+
* Throws {@link FreeTextError} for input mistakes; callers are expected to
|
|
79
|
+
* surface the error with the standard `(<code>): <message>` rendering and
|
|
80
|
+
* exit non-zero before any network call is made.
|
|
81
|
+
*/
|
|
82
|
+
export declare function resolveFreeText(rawValue: string | undefined, options: ResolveFreeTextOptions): Promise<string | undefined>;
|
|
83
|
+
//# sourceMappingURL=freetext.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"freetext.d.ts","sourceRoot":"","sources":["../../src/lib/freetext.ts"],"names":[],"mappings":"AAGA,OAAO,EAAqB,KAAK,IAAI,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAK9E;;;;;;GAMG;AACH,MAAM,MAAM,iBAAiB,GACzB,eAAe,GACf,gBAAgB,GAChB,iBAAiB,GACjB,mBAAmB,GACnB,oBAAoB,GACpB,eAAe,CAAC;AAEpB;;;;;;;;;GASG;AACH,qBAAa,aAAc,SAAQ,KAAK;aAGpB,IAAI,EAAE,iBAAiB;IAFzC,SAAkB,IAAI,mBAAmB;gBAEvB,IAAI,EAAE,iBAAiB,EACvC,OAAO,EAAE,MAAM;CAIlB;AAED;;;;;;GAMG;AACH,MAAM,WAAW,sBAAsB;IACrC,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B,0EAA0E;IAC1E,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAE/B,gEAAgE;IAChE,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAEhC,iFAAiF;IACjF,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAE5B,2DAA2D;IAC3D,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC,cAAc,CAAC;IAEvC,qEAAqE;IACrE,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;IAEtD,wEAAwE;IACxE,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,YAAY,CAAC;CACtC;AAQD;;;;;;GAMG;AACH,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAsB,eAAe,CACnC,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,OAAO,EAAE,sBAAsB,GAC9B,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAwD7B"}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { spawn as defaultSpawn } from "node:child_process";
|
|
4
|
+
import { mkdtemp, readFile as defaultReadFile, rm, writeFile } from "node:fs/promises";
|
|
5
|
+
import { tmpdir } from "node:os";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
/**
|
|
8
|
+
* Typed error thrown by {@link resolveFreeText} for input mistakes the user
|
|
9
|
+
* must fix before retrying. Callers render the standard
|
|
10
|
+
* `<command> failed (<code>): <message>` shape and exit non-zero.
|
|
11
|
+
*
|
|
12
|
+
* Production failures from the API or the platform stay typed as their
|
|
13
|
+
* domain errors (e.g. `profile.basic.ProfileError`, `TtctlError`); this
|
|
14
|
+
* type covers ONLY input-resolution failures that happen on the local
|
|
15
|
+
* machine before any network call.
|
|
16
|
+
*/
|
|
17
|
+
export class FreeTextError extends Error {
|
|
18
|
+
code;
|
|
19
|
+
name = "FreeTextError";
|
|
20
|
+
constructor(code, message) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.code = code;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
// Module-level guard for the "two flags both want stdin" diagnostic. Once
|
|
26
|
+
// any caller has consumed stdin in this process, a second `-` claim throws
|
|
27
|
+
// `STDIN_DOUBLE_CLAIM` instead of reading already-empty input. Tests reset
|
|
28
|
+
// this via {@link _resetStdinClaimForTesting}.
|
|
29
|
+
let stdinClaimed = false;
|
|
30
|
+
/**
|
|
31
|
+
* Reset the module-level stdin-claim guard. Test-only. Production callers
|
|
32
|
+
* must not call this — the guard exists precisely to prevent the same
|
|
33
|
+
* process from consuming stdin twice in a single CLI invocation.
|
|
34
|
+
*
|
|
35
|
+
* @internal
|
|
36
|
+
*/
|
|
37
|
+
export function _resetStdinClaimForTesting() {
|
|
38
|
+
stdinClaimed = false;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Resolve a free-text flag value through the four supported input modes.
|
|
42
|
+
*
|
|
43
|
+
* Modes (in priority order):
|
|
44
|
+
*
|
|
45
|
+
* 1. **Editor** — `enableEditor === true` opens `$EDITOR` seeded with
|
|
46
|
+
* `currentValue` and returns the saved buffer. Combining `enableEditor`
|
|
47
|
+
* with a defined `rawValue` is ambiguous; the helper rejects it before
|
|
48
|
+
* any I/O.
|
|
49
|
+
* 2. **Stdin** — `rawValue === "-"` reads `process.stdin` (or the injected
|
|
50
|
+
* stream) until EOF. Empty stdin is NOT an error — it returns the empty
|
|
51
|
+
* string, per AC. A non-piped TTY surfaces `STDIN_UNAVAILABLE` rather
|
|
52
|
+
* than hanging the CLI forever waiting on an interactive user.
|
|
53
|
+
* 3. **File** — `rawValue.startsWith("@")` reads the file at the path that
|
|
54
|
+
* follows the `@` and returns its UTF-8 contents. ENOENT becomes
|
|
55
|
+
* `FILE_NOT_FOUND`; any other read failure becomes `FILE_READ_ERROR`.
|
|
56
|
+
* 4. **Inline** — any other defined `rawValue` is returned verbatim.
|
|
57
|
+
*
|
|
58
|
+
* Returns `undefined` when neither `rawValue` is defined nor `enableEditor`
|
|
59
|
+
* is set — this is the "user did not pass the flag" case, which the caller
|
|
60
|
+
* usually branches on to leave the field unchanged.
|
|
61
|
+
*
|
|
62
|
+
* Throws {@link FreeTextError} for input mistakes; callers are expected to
|
|
63
|
+
* surface the error with the standard `(<code>): <message>` rendering and
|
|
64
|
+
* exit non-zero before any network call is made.
|
|
65
|
+
*/
|
|
66
|
+
export async function resolveFreeText(rawValue, options) {
|
|
67
|
+
const { flagName } = options;
|
|
68
|
+
const enableEditor = options.enableEditor ?? false;
|
|
69
|
+
// Mode-conflict gate: combining `--edit` with any concrete value (inline,
|
|
70
|
+
// `-`, or `@path`) is ambiguous about which side wins, so we refuse to
|
|
71
|
+
// guess. Catches all three cross-mode combinations in a single check.
|
|
72
|
+
if (enableEditor && rawValue !== undefined) {
|
|
73
|
+
throw new FreeTextError("MODE_CONFLICT", `--edit cannot be combined with --${flagName} <value>; pick one input mode`);
|
|
74
|
+
}
|
|
75
|
+
if (enableEditor) {
|
|
76
|
+
const editor = options.editorEnv ?? process.env.EDITOR ?? "vi";
|
|
77
|
+
const seed = options.currentValue ?? "";
|
|
78
|
+
return invokeEditor(editor, seed, options.spawn ?? defaultSpawn);
|
|
79
|
+
}
|
|
80
|
+
if (rawValue === undefined)
|
|
81
|
+
return undefined;
|
|
82
|
+
if (rawValue === "-") {
|
|
83
|
+
if (stdinClaimed) {
|
|
84
|
+
throw new FreeTextError("STDIN_DOUBLE_CLAIM", `--${flagName}: stdin already consumed by an earlier flag; only one flag may read stdin per invocation`);
|
|
85
|
+
}
|
|
86
|
+
const stream = options.stdin ?? process.stdin;
|
|
87
|
+
if (isTtyStream(stream)) {
|
|
88
|
+
throw new FreeTextError("STDIN_UNAVAILABLE", `--${flagName}: stdin requested ('-') but no input is being piped; pipe via shell or use @path`);
|
|
89
|
+
}
|
|
90
|
+
stdinClaimed = true;
|
|
91
|
+
return readAllFromStream(stream);
|
|
92
|
+
}
|
|
93
|
+
if (rawValue.startsWith("@")) {
|
|
94
|
+
const filePath = rawValue.slice(1);
|
|
95
|
+
const reader = options.readFile ?? defaultReader;
|
|
96
|
+
try {
|
|
97
|
+
return await reader(filePath);
|
|
98
|
+
}
|
|
99
|
+
catch (err) {
|
|
100
|
+
const code = err.code;
|
|
101
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
102
|
+
if (code === "ENOENT") {
|
|
103
|
+
throw new FreeTextError("FILE_NOT_FOUND", `--${flagName}: file not found: ${filePath}`);
|
|
104
|
+
}
|
|
105
|
+
throw new FreeTextError("FILE_READ_ERROR", `--${flagName}: failed to read ${filePath}: ${message}`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
return rawValue;
|
|
109
|
+
}
|
|
110
|
+
const defaultReader = (path) => defaultReadFile(path, "utf-8");
|
|
111
|
+
function isTtyStream(stream) {
|
|
112
|
+
// `process.stdin` (a `tty.ReadStream`) carries `isTTY: true` when the
|
|
113
|
+
// user is running an interactive shell with no piped input. Non-TTY
|
|
114
|
+
// streams (test fakes, real pipes) lack the property at runtime even
|
|
115
|
+
// though `NodeJS.ReadStream` types it as a definite `boolean` — narrow
|
|
116
|
+
// through a structural cast so the missing-property case becomes
|
|
117
|
+
// `false` rather than a thrown access.
|
|
118
|
+
const maybeTty = stream;
|
|
119
|
+
return maybeTty.isTTY === true;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Read the entire stream as a UTF-8 string. The encoding is set on the
|
|
123
|
+
* stream so iteration yields strings, not Buffers — this also keeps a
|
|
124
|
+
* single decoder across chunks (avoids splitting a multi-byte character
|
|
125
|
+
* across two reads).
|
|
126
|
+
*/
|
|
127
|
+
async function readAllFromStream(stream) {
|
|
128
|
+
stream.setEncoding("utf-8");
|
|
129
|
+
let buf = "";
|
|
130
|
+
for await (const chunk of stream) {
|
|
131
|
+
buf += String(chunk);
|
|
132
|
+
}
|
|
133
|
+
return buf;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Edit-in-`$EDITOR` flow. Writes `seed` to a randomly-named file in
|
|
137
|
+
* `os.tmpdir()`, spawns the editor with `stdio: "inherit"` so the editor
|
|
138
|
+
* directly owns the user's TTY, awaits exit, reads the saved buffer, and
|
|
139
|
+
* cleans up the temp directory in `finally` even on editor failure.
|
|
140
|
+
*
|
|
141
|
+
* The editor process inherits stdio so the user sees the editor UI
|
|
142
|
+
* directly; the helper itself produces no terminal output during the edit.
|
|
143
|
+
*/
|
|
144
|
+
async function invokeEditor(editor, seed, spawn) {
|
|
145
|
+
const dir = await mkdtemp(join(tmpdir(), "ttctl-edit-"));
|
|
146
|
+
const tempFile = join(dir, "buffer.txt");
|
|
147
|
+
try {
|
|
148
|
+
await writeFile(tempFile, seed, "utf-8");
|
|
149
|
+
await new Promise((resolve, reject) => {
|
|
150
|
+
const child = spawn(editor, [tempFile], { stdio: "inherit" });
|
|
151
|
+
let settled = false;
|
|
152
|
+
child.on("error", (err) => {
|
|
153
|
+
if (settled)
|
|
154
|
+
return;
|
|
155
|
+
settled = true;
|
|
156
|
+
reject(new FreeTextError("EDITOR_FAILED", `failed to launch editor '${editor}': ${err.message}`));
|
|
157
|
+
});
|
|
158
|
+
child.on("close", (code) => {
|
|
159
|
+
if (settled)
|
|
160
|
+
return;
|
|
161
|
+
settled = true;
|
|
162
|
+
if (code === 0) {
|
|
163
|
+
resolve();
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
reject(new FreeTextError("EDITOR_FAILED", `editor '${editor}' exited with code ${String(code)}`));
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
});
|
|
170
|
+
// `return await` inside try/finally ensures the cleanup in `finally`
|
|
171
|
+
// runs AFTER the read settles, not concurrently with it.
|
|
172
|
+
return await defaultReadFile(tempFile, "utf-8");
|
|
173
|
+
}
|
|
174
|
+
finally {
|
|
175
|
+
await rm(dir, { recursive: true, force: true }).catch(() => {
|
|
176
|
+
// Cleanup is best-effort: the OS reaps `tmpdir` entries periodically
|
|
177
|
+
// anyway, and surfacing a cleanup failure would mask the actual
|
|
178
|
+
// editor result the caller cares about.
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
//# sourceMappingURL=freetext.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"freetext.js","sourceRoot":"","sources":["../../src/lib/freetext.ts"],"names":[],"mappings":"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"}
|