@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,121 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { Command, Option } from "commander";
|
|
4
|
+
import { OUTPUT_FORMATS } from "../../../lib/output.js";
|
|
5
|
+
import { runProfilePortfolioAdd } from "./add.js";
|
|
6
|
+
import { runProfilePortfolioHighlight } from "./highlight.js";
|
|
7
|
+
import { runProfilePortfolioList } from "./list.js";
|
|
8
|
+
import { runProfilePortfolioRemove } from "./remove.js";
|
|
9
|
+
import { runProfilePortfolioReorder } from "./reorder.js";
|
|
10
|
+
import { runProfilePortfolioUpdate } from "./update.js";
|
|
11
|
+
import { runProfilePortfolioUpload } from "./upload.js";
|
|
12
|
+
/**
|
|
13
|
+
* Build the `ttctl profile portfolio` command tree.
|
|
14
|
+
*
|
|
15
|
+
* The canonical sub-domain name is `portfolio`; the CLI registers
|
|
16
|
+
* `projects` as a Commander.js alias so users can type either form. Per
|
|
17
|
+
* project policy (see issue #72), aliases are CLI-only — MCP tool names
|
|
18
|
+
* use ONLY the canonical name.
|
|
19
|
+
*
|
|
20
|
+
* The seven leaves follow the verb economy from the #68 epic:
|
|
21
|
+
* `add / update / remove / list / reorder / highlight / upload`. The
|
|
22
|
+
* `update` verb name is the user-facing CLI form; the core function is
|
|
23
|
+
* `update()` (no rename — verbs match between CLI and core for portfolio).
|
|
24
|
+
*/
|
|
25
|
+
export function buildProfilePortfolioCommand() {
|
|
26
|
+
const portfolio = new Command("portfolio")
|
|
27
|
+
.alias("projects")
|
|
28
|
+
.description("View and update the portfolio section of your profile");
|
|
29
|
+
portfolio
|
|
30
|
+
.command("add")
|
|
31
|
+
.description("Create a new portfolio item")
|
|
32
|
+
.requiredOption("--title <text>", "portfolio item title")
|
|
33
|
+
.option("--description <text>", 'item description (inline text, "-" for stdin, or "@path" to read from file)')
|
|
34
|
+
.option("--edit", "open $EDITOR to compose the description interactively")
|
|
35
|
+
.option("--url <url>", "primary URL for the item (alias for --link)")
|
|
36
|
+
.option("--link <url>", "primary URL for the item (canonical flag, equivalent to --url)")
|
|
37
|
+
.option("--cover <file>", "path to a cover-image file to upload alongside the item")
|
|
38
|
+
.option("--industry-id <id>", 'catalog Industry id (repeatable; required — at least one). Discover via `ttctl profile industries autocomplete "<query>"`.', (value, prev) => (prev ? [...prev, value] : [value]))
|
|
39
|
+
.addOption(new Option("-o, --output <format>", "output format")
|
|
40
|
+
.choices(OUTPUT_FORMATS)
|
|
41
|
+
.default("pretty"))
|
|
42
|
+
.action(async (options) => {
|
|
43
|
+
await runProfilePortfolioAdd(options);
|
|
44
|
+
});
|
|
45
|
+
portfolio
|
|
46
|
+
.command("update")
|
|
47
|
+
.description("Update fields on a portfolio item")
|
|
48
|
+
.argument("<id>", "id of the portfolio item to update")
|
|
49
|
+
.option("--title <text>", "portfolio item title")
|
|
50
|
+
.option("--description <text>", 'item description (inline text, "-" for stdin, or "@path" to read from file)')
|
|
51
|
+
.option("--edit", "open $EDITOR to compose the description interactively")
|
|
52
|
+
.option("--url <url>", "primary URL for the item (alias for --link)")
|
|
53
|
+
.option("--link <url>", "primary URL for the item (canonical flag, equivalent to --url)")
|
|
54
|
+
.option("--client <name>", "client/company name")
|
|
55
|
+
.option("--accomplishment <text>", "accomplishment summary")
|
|
56
|
+
.addOption(new Option("-o, --output <format>", "output format")
|
|
57
|
+
.choices(OUTPUT_FORMATS)
|
|
58
|
+
.default("pretty"))
|
|
59
|
+
.action(async (id, options) => {
|
|
60
|
+
await runProfilePortfolioUpdate(id, options);
|
|
61
|
+
});
|
|
62
|
+
portfolio
|
|
63
|
+
.command("remove")
|
|
64
|
+
.alias("rm")
|
|
65
|
+
.description("Remove a portfolio item")
|
|
66
|
+
.argument("<id>", "id of the portfolio item to remove")
|
|
67
|
+
.addOption(new Option("-o, --output <format>", "output format")
|
|
68
|
+
.choices(OUTPUT_FORMATS)
|
|
69
|
+
.default("pretty"))
|
|
70
|
+
.action(async (id, options) => {
|
|
71
|
+
await runProfilePortfolioRemove(id, options.output);
|
|
72
|
+
});
|
|
73
|
+
portfolio
|
|
74
|
+
.command("list")
|
|
75
|
+
.description("List portfolio items")
|
|
76
|
+
.addOption(new Option("-o, --output <format>", "output format")
|
|
77
|
+
.choices(OUTPUT_FORMATS)
|
|
78
|
+
.default("pretty"))
|
|
79
|
+
.action(async (options) => {
|
|
80
|
+
await runProfilePortfolioList(options.output);
|
|
81
|
+
});
|
|
82
|
+
portfolio
|
|
83
|
+
.command("reorder")
|
|
84
|
+
.description("Reorder a portfolio item")
|
|
85
|
+
.argument("<id>", "id of the portfolio item to move")
|
|
86
|
+
.option("--before <id>", "place the item immediately before this neighbour id")
|
|
87
|
+
.option("--after <id>", "place the item immediately after this neighbour id")
|
|
88
|
+
.option("--to <position>", "place the item at this absolute 0-based position")
|
|
89
|
+
.addOption(new Option("-o, --output <format>", "output format")
|
|
90
|
+
.choices(OUTPUT_FORMATS)
|
|
91
|
+
.default("pretty"))
|
|
92
|
+
.action(async (id, options) => {
|
|
93
|
+
await runProfilePortfolioReorder(id, options);
|
|
94
|
+
});
|
|
95
|
+
portfolio
|
|
96
|
+
.command("highlight")
|
|
97
|
+
.description("Toggle the highlight flag on a portfolio item (default: enable)")
|
|
98
|
+
.argument("<id>", "id of the portfolio item to highlight")
|
|
99
|
+
.option("--off", "clear the highlight flag instead of setting it")
|
|
100
|
+
.addOption(new Option("-o, --output <format>", "output format")
|
|
101
|
+
.choices(OUTPUT_FORMATS)
|
|
102
|
+
.default("pretty"))
|
|
103
|
+
.action(async (id, options) => {
|
|
104
|
+
await runProfilePortfolioHighlight(id, options);
|
|
105
|
+
});
|
|
106
|
+
portfolio
|
|
107
|
+
.command("upload")
|
|
108
|
+
.description("Upload a cover image (--cover) or attachment file (--file) for the user's portfolio")
|
|
109
|
+
.argument("[id]", "(unused; reserved for future per-item upload routing)")
|
|
110
|
+
.option("--cover <file>", "path to a cover-image file to upload")
|
|
111
|
+
.option("--file <file>", "path to a portfolio-attachment file to upload")
|
|
112
|
+
.option("--crop <x,y,w,h>", "cover crop (px), comma-separated x,y,w,h; default: whole image (PNG) or sentinel oversize")
|
|
113
|
+
.addOption(new Option("-o, --output <format>", "output format")
|
|
114
|
+
.choices(OUTPUT_FORMATS)
|
|
115
|
+
.default("pretty"))
|
|
116
|
+
.action(async (id, options) => {
|
|
117
|
+
await runProfilePortfolioUpload(id, options);
|
|
118
|
+
});
|
|
119
|
+
return portfolio;
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/commands/profile/portfolio/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { profile } from "@ttctl/core";
|
|
2
|
+
import type { OutputFormat } from "../../../lib/output.js";
|
|
3
|
+
/**
|
|
4
|
+
* Action handler for `ttctl profile portfolio list`. Reads the user's
|
|
5
|
+
* portfolio collection and emits it via the cross-CLI output helper
|
|
6
|
+
* (`packages/cli/src/lib/output.ts` from #71), wrapped in the v0.4
|
|
7
|
+
* list envelope (`{version, items, pageInfo?}` from #128) for
|
|
8
|
+
* json/yaml.
|
|
9
|
+
*
|
|
10
|
+
* Per #129, the `pretty` slot is registered with `emitResult` and
|
|
11
|
+
* unwraps the envelope's `items` field for the curated multi-line
|
|
12
|
+
* layout that surfaces `description`, `accomplishment`, `coverImage`,
|
|
13
|
+
* and `clientOrCompanyName` (the audit-confirmed dropped fields from
|
|
14
|
+
* #124). The `table` slot is also wired (also unwrapping `items`) —
|
|
15
|
+
* `formatResult`'s shape dispatcher prefers `table` for list-shape
|
|
16
|
+
* data when present, but the audit's Override Registry Decisions
|
|
17
|
+
* endorse routing portfolio list to multi-line because
|
|
18
|
+
* `description`/`accomplishment` are paragraph-length and the
|
|
19
|
+
* row-based table layout collapses them. {@link formatPortfolioTable}
|
|
20
|
+
* stays exported for direct test use and future override-dispatch
|
|
21
|
+
* wiring.
|
|
22
|
+
*
|
|
23
|
+
* Empty case is handled by the shared empty-state wrapper (#122) via
|
|
24
|
+
* `empty: { command: "profile.portfolio.list" }`. The wrapper detects
|
|
25
|
+
* both `[]` and `{items: []}` shapes (per #122's `isEmptyCollection`),
|
|
26
|
+
* so the post-#128 envelope wrapping continues to short-circuit
|
|
27
|
+
* BEFORE per-format dispatch — emitting `"No portfolio items found.
|
|
28
|
+
* Add one with: ttctl profile portfolio add"` for `pretty`, `[]` for
|
|
29
|
+
* `json`. The formatters keep a defensive empty-list branch for
|
|
30
|
+
* direct callers (tests, future programmatic use) that bypass the
|
|
31
|
+
* action handler.
|
|
32
|
+
*/
|
|
33
|
+
export declare function runProfilePortfolioList(format: OutputFormat): Promise<void>;
|
|
34
|
+
/**
|
|
35
|
+
* Format the portfolio list as the post-#129 `pretty` summary. Pure —
|
|
36
|
+
* no I/O — directly unit-testable.
|
|
37
|
+
*
|
|
38
|
+
* Per-item layout, indented two spaces from the count header:
|
|
39
|
+
*
|
|
40
|
+
* <id>[ ★] <title>
|
|
41
|
+
* Client: <clientOrCompanyName> // skip-if-null
|
|
42
|
+
* URL: <link> // skip-if-null
|
|
43
|
+
* Cover: <coverImage> // skip-if-null
|
|
44
|
+
* Description: // always (renders (unset) on null)
|
|
45
|
+
* <body, paragraph breaks preserved>
|
|
46
|
+
* Accomplishment: // skip-if-null (multi-paragraph)
|
|
47
|
+
* <body>
|
|
48
|
+
*
|
|
49
|
+
* Items are separated by a single blank line. Field ordering for each
|
|
50
|
+
* item: identity (id, highlight star, title) first, then user-edited
|
|
51
|
+
* narrative (client, url, cover, description, accomplishment) — most
|
|
52
|
+
* user-edited last because they're the multi-line block fields that
|
|
53
|
+
* benefit from sticking to the bottom of the item.
|
|
54
|
+
*
|
|
55
|
+
* Closes the audit-confirmed formatter-root-cause defect from #124:
|
|
56
|
+
* `description`, `accomplishment`, `coverImage`, and
|
|
57
|
+
* `clientOrCompanyName` are now visible in the default output (the
|
|
58
|
+
* pre-#129 formatter dropped 7 of 12 entity fields).
|
|
59
|
+
*
|
|
60
|
+
* `tags` and `media` are NOT on the wire `PortfolioItem` — neither the
|
|
61
|
+
* mobile-gateway nor the talent-profile schema declares them. The audit
|
|
62
|
+
* flagged them as suspect; #127 verified absence empirically. They are
|
|
63
|
+
* deliberately omitted here.
|
|
64
|
+
*
|
|
65
|
+
* Pretty does NOT truncate (per the issue AC: "For long URLs / IDs:
|
|
66
|
+
* don't truncate (this is `pretty`, not `table`)"); the terminal wraps
|
|
67
|
+
* if the user's window is narrow.
|
|
68
|
+
*/
|
|
69
|
+
export declare function formatPortfolioPretty(items: profile.portfolio.PortfolioItem[]): string;
|
|
70
|
+
/**
|
|
71
|
+
* Format the portfolio list as a `cli-table3`-rendered table sized to
|
|
72
|
+
* the current terminal width. Restores the `clientOrCompanyName` column
|
|
73
|
+
* dropped by the pre-#129 formatter (audit-confirmed asymmetric drop:
|
|
74
|
+
* `text` had it, `table` didn't).
|
|
75
|
+
*
|
|
76
|
+
* Long-form fields (`description`, `accomplishment`) are NOT in the
|
|
77
|
+
* table — paragraph-length text doesn't fit a row layout. The override
|
|
78
|
+
* registry in `lib/format-overrides.ts` flags `profile portfolio list`
|
|
79
|
+
* as a candidate for the `multi-line` strategy; users wanting the full
|
|
80
|
+
* detail land on `pretty` (the post-#126 default).
|
|
81
|
+
*/
|
|
82
|
+
export declare function formatPortfolioTable(items: profile.portfolio.PortfolioItem[], terminalWidth?: number): string;
|
|
83
|
+
//# sourceMappingURL=list.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.d.ts","sourceRoot":"","sources":["../../../../src/commands/profile/portfolio/list.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAKtC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAI3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAsB,uBAAuB,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAgBjF;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,aAAa,EAAE,GAAG,MAAM,CAMtF;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,KAAK,EAAE,OAAO,CAAC,SAAS,CAAC,aAAa,EAAE,EACxC,aAAa,GAAE,MAAqC,GACnD,MAAM,CAsBR"}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import Table from "cli-table3";
|
|
4
|
+
import { profile } from "@ttctl/core";
|
|
5
|
+
import { wrapListEnvelope } from "../../../lib/envelopes.js";
|
|
6
|
+
import { renderMultiParagraph, unsetOr } from "../../../lib/format-helpers.js";
|
|
7
|
+
import { emitResult } from "../../../lib/output.js";
|
|
8
|
+
import { handlePortfolioError } from "./add.js";
|
|
9
|
+
import { loadAuthTokenOrExit } from "./shared.js";
|
|
10
|
+
/**
|
|
11
|
+
* Action handler for `ttctl profile portfolio list`. Reads the user's
|
|
12
|
+
* portfolio collection and emits it via the cross-CLI output helper
|
|
13
|
+
* (`packages/cli/src/lib/output.ts` from #71), wrapped in the v0.4
|
|
14
|
+
* list envelope (`{version, items, pageInfo?}` from #128) for
|
|
15
|
+
* json/yaml.
|
|
16
|
+
*
|
|
17
|
+
* Per #129, the `pretty` slot is registered with `emitResult` and
|
|
18
|
+
* unwraps the envelope's `items` field for the curated multi-line
|
|
19
|
+
* layout that surfaces `description`, `accomplishment`, `coverImage`,
|
|
20
|
+
* and `clientOrCompanyName` (the audit-confirmed dropped fields from
|
|
21
|
+
* #124). The `table` slot is also wired (also unwrapping `items`) —
|
|
22
|
+
* `formatResult`'s shape dispatcher prefers `table` for list-shape
|
|
23
|
+
* data when present, but the audit's Override Registry Decisions
|
|
24
|
+
* endorse routing portfolio list to multi-line because
|
|
25
|
+
* `description`/`accomplishment` are paragraph-length and the
|
|
26
|
+
* row-based table layout collapses them. {@link formatPortfolioTable}
|
|
27
|
+
* stays exported for direct test use and future override-dispatch
|
|
28
|
+
* wiring.
|
|
29
|
+
*
|
|
30
|
+
* Empty case is handled by the shared empty-state wrapper (#122) via
|
|
31
|
+
* `empty: { command: "profile.portfolio.list" }`. The wrapper detects
|
|
32
|
+
* both `[]` and `{items: []}` shapes (per #122's `isEmptyCollection`),
|
|
33
|
+
* so the post-#128 envelope wrapping continues to short-circuit
|
|
34
|
+
* BEFORE per-format dispatch — emitting `"No portfolio items found.
|
|
35
|
+
* Add one with: ttctl profile portfolio add"` for `pretty`, `[]` for
|
|
36
|
+
* `json`. The formatters keep a defensive empty-list branch for
|
|
37
|
+
* direct callers (tests, future programmatic use) that bypass the
|
|
38
|
+
* action handler.
|
|
39
|
+
*/
|
|
40
|
+
export async function runProfilePortfolioList(format) {
|
|
41
|
+
const token = await loadAuthTokenOrExit("portfolio list", format);
|
|
42
|
+
let items;
|
|
43
|
+
try {
|
|
44
|
+
items = await profile.portfolio.list(token);
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
handlePortfolioError("portfolio list", err, format);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
emitResult(wrapListEnvelope(items), format, {
|
|
51
|
+
pretty: (data) => formatPortfolioPretty(data.items),
|
|
52
|
+
table: (data) => formatPortfolioTable(data.items),
|
|
53
|
+
empty: { command: "profile.portfolio.list" },
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Format the portfolio list as the post-#129 `pretty` summary. Pure —
|
|
58
|
+
* no I/O — directly unit-testable.
|
|
59
|
+
*
|
|
60
|
+
* Per-item layout, indented two spaces from the count header:
|
|
61
|
+
*
|
|
62
|
+
* <id>[ ★] <title>
|
|
63
|
+
* Client: <clientOrCompanyName> // skip-if-null
|
|
64
|
+
* URL: <link> // skip-if-null
|
|
65
|
+
* Cover: <coverImage> // skip-if-null
|
|
66
|
+
* Description: // always (renders (unset) on null)
|
|
67
|
+
* <body, paragraph breaks preserved>
|
|
68
|
+
* Accomplishment: // skip-if-null (multi-paragraph)
|
|
69
|
+
* <body>
|
|
70
|
+
*
|
|
71
|
+
* Items are separated by a single blank line. Field ordering for each
|
|
72
|
+
* item: identity (id, highlight star, title) first, then user-edited
|
|
73
|
+
* narrative (client, url, cover, description, accomplishment) — most
|
|
74
|
+
* user-edited last because they're the multi-line block fields that
|
|
75
|
+
* benefit from sticking to the bottom of the item.
|
|
76
|
+
*
|
|
77
|
+
* Closes the audit-confirmed formatter-root-cause defect from #124:
|
|
78
|
+
* `description`, `accomplishment`, `coverImage`, and
|
|
79
|
+
* `clientOrCompanyName` are now visible in the default output (the
|
|
80
|
+
* pre-#129 formatter dropped 7 of 12 entity fields).
|
|
81
|
+
*
|
|
82
|
+
* `tags` and `media` are NOT on the wire `PortfolioItem` — neither the
|
|
83
|
+
* mobile-gateway nor the talent-profile schema declares them. The audit
|
|
84
|
+
* flagged them as suspect; #127 verified absence empirically. They are
|
|
85
|
+
* deliberately omitted here.
|
|
86
|
+
*
|
|
87
|
+
* Pretty does NOT truncate (per the issue AC: "For long URLs / IDs:
|
|
88
|
+
* don't truncate (this is `pretty`, not `table`)"); the terminal wraps
|
|
89
|
+
* if the user's window is narrow.
|
|
90
|
+
*/
|
|
91
|
+
export function formatPortfolioPretty(items) {
|
|
92
|
+
if (items.length === 0)
|
|
93
|
+
return "(no portfolio items)";
|
|
94
|
+
const headerLine = `${items.length.toString()} portfolio item${items.length === 1 ? "" : "s"}:`;
|
|
95
|
+
const itemBlocks = items.map((it) => renderPortfolioItem(it));
|
|
96
|
+
return [headerLine, "", ...joinWithSeparator(itemBlocks, "")].join("\n");
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Format the portfolio list as a `cli-table3`-rendered table sized to
|
|
100
|
+
* the current terminal width. Restores the `clientOrCompanyName` column
|
|
101
|
+
* dropped by the pre-#129 formatter (audit-confirmed asymmetric drop:
|
|
102
|
+
* `text` had it, `table` didn't).
|
|
103
|
+
*
|
|
104
|
+
* Long-form fields (`description`, `accomplishment`) are NOT in the
|
|
105
|
+
* table — paragraph-length text doesn't fit a row layout. The override
|
|
106
|
+
* registry in `lib/format-overrides.ts` flags `profile portfolio list`
|
|
107
|
+
* as a candidate for the `multi-line` strategy; users wanting the full
|
|
108
|
+
* detail land on `pretty` (the post-#126 default).
|
|
109
|
+
*/
|
|
110
|
+
export function formatPortfolioTable(items, terminalWidth = process.stdout.columns || 80) {
|
|
111
|
+
if (items.length === 0) {
|
|
112
|
+
const empty = new Table({ head: ["id", "title", "highlight", "client", "link"] });
|
|
113
|
+
return empty.toString();
|
|
114
|
+
}
|
|
115
|
+
const idWidth = 14;
|
|
116
|
+
const highlightWidth = 12;
|
|
117
|
+
// Three text columns share the remaining width: title, client, link.
|
|
118
|
+
// Borders + outer padding consume ~7 chars total.
|
|
119
|
+
const remaining = Math.max(60, terminalWidth - idWidth - highlightWidth - 7);
|
|
120
|
+
const titleWidth = Math.max(15, Math.floor(remaining / 3));
|
|
121
|
+
const clientWidth = Math.max(15, Math.floor(remaining / 3));
|
|
122
|
+
const linkWidth = Math.max(15, remaining - titleWidth - clientWidth);
|
|
123
|
+
const table = new Table({
|
|
124
|
+
head: ["id", "title", "highlight", "client", "link"],
|
|
125
|
+
colWidths: [idWidth, titleWidth, highlightWidth, clientWidth, linkWidth],
|
|
126
|
+
wordWrap: true,
|
|
127
|
+
});
|
|
128
|
+
for (const it of items) {
|
|
129
|
+
table.push([it.id, it.title ?? "", it.highlight ? "★" : "", it.clientOrCompanyName ?? "", it.link ?? ""]);
|
|
130
|
+
}
|
|
131
|
+
return table.toString();
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Render one portfolio item as a multi-line block. The block is indented
|
|
135
|
+
* two spaces from the count header; the per-field detail is indented
|
|
136
|
+
* four spaces total (block indent + nested indent).
|
|
137
|
+
*/
|
|
138
|
+
function renderPortfolioItem(it) {
|
|
139
|
+
const blockIndent = " ";
|
|
140
|
+
const detailIndent = " ";
|
|
141
|
+
const star = it.highlight ? " ★" : "";
|
|
142
|
+
const title = it.title ?? "(untitled)";
|
|
143
|
+
const lines = [`${blockIndent}${it.id}${star} ${title}`];
|
|
144
|
+
if (it.clientOrCompanyName !== null) {
|
|
145
|
+
lines.push(`${detailIndent}Client: ${it.clientOrCompanyName}`);
|
|
146
|
+
}
|
|
147
|
+
if (it.link !== null) {
|
|
148
|
+
lines.push(`${detailIndent}URL: ${it.link}`);
|
|
149
|
+
}
|
|
150
|
+
if (it.coverImage !== null) {
|
|
151
|
+
lines.push(`${detailIndent}Cover: ${it.coverImage}`);
|
|
152
|
+
}
|
|
153
|
+
// Description always emits — it's the primary user-edited field, so
|
|
154
|
+
// the (unset) marker is itself the "you can edit this" signal. Multi-
|
|
155
|
+
// paragraph rendering preserves `\n\n` as actual blank lines.
|
|
156
|
+
if (it.description !== null && it.description !== "") {
|
|
157
|
+
lines.push(renderMultiParagraph("Description", it.description, detailIndent));
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
lines.push(`${detailIndent}Description: ${unsetOr(null)}`);
|
|
161
|
+
}
|
|
162
|
+
// Accomplishment is skip-if-null per the AC's "if present" qualifier
|
|
163
|
+
// — it's secondary narrative content; rendering (unset) for every
|
|
164
|
+
// item without one would clutter long lists.
|
|
165
|
+
if (it.accomplishment !== null && it.accomplishment !== "") {
|
|
166
|
+
lines.push(renderMultiParagraph("Accomplishment", it.accomplishment, detailIndent));
|
|
167
|
+
}
|
|
168
|
+
return lines.join("\n");
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Interleave `parts` with `separator` between every adjacent pair, like
|
|
172
|
+
* `parts.join(separator)` but yielding a string array suitable for
|
|
173
|
+
* splicing into a larger `lines` array via the spread operator.
|
|
174
|
+
*
|
|
175
|
+
* Used to produce the visible blank-line delimiter between portfolio
|
|
176
|
+
* items without a trailing separator after the last item.
|
|
177
|
+
*/
|
|
178
|
+
function joinWithSeparator(parts, separator) {
|
|
179
|
+
const out = [];
|
|
180
|
+
for (let i = 0; i < parts.length; i++) {
|
|
181
|
+
if (i > 0)
|
|
182
|
+
out.push(separator);
|
|
183
|
+
const part = parts[i];
|
|
184
|
+
if (part !== undefined)
|
|
185
|
+
out.push(part);
|
|
186
|
+
}
|
|
187
|
+
return out;
|
|
188
|
+
}
|
|
189
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../../../src/commands/profile/portfolio/list.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { OutputFormat } from "../../../lib/output.js";
|
|
2
|
+
/**
|
|
3
|
+
* Action handler for `ttctl profile portfolio remove <id>` (alias `rm`).
|
|
4
|
+
* Removes the portfolio item by id; emits the v0.4 envelope (#128) with
|
|
5
|
+
* `removed: {id}` and renders the post-removal list under the success
|
|
6
|
+
* line in pretty mode.
|
|
7
|
+
*/
|
|
8
|
+
export declare function runProfilePortfolioRemove(id: string, format: OutputFormat): Promise<void>;
|
|
9
|
+
//# sourceMappingURL=remove.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove.d.ts","sourceRoot":"","sources":["../../../../src/commands/profile/portfolio/remove.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAI3D;;;;;GAKG;AACH,wBAAsB,yBAAyB,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CAY/F"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { profile } from "@ttctl/core";
|
|
4
|
+
import { emitMutationResult, handlePortfolioError } from "./add.js";
|
|
5
|
+
import { loadAuthTokenOrExit } from "./shared.js";
|
|
6
|
+
/**
|
|
7
|
+
* Action handler for `ttctl profile portfolio remove <id>` (alias `rm`).
|
|
8
|
+
* Removes the portfolio item by id; emits the v0.4 envelope (#128) with
|
|
9
|
+
* `removed: {id}` and renders the post-removal list under the success
|
|
10
|
+
* line in pretty mode.
|
|
11
|
+
*/
|
|
12
|
+
export async function runProfilePortfolioRemove(id, format) {
|
|
13
|
+
const token = await loadAuthTokenOrExit("portfolio remove", format);
|
|
14
|
+
let items;
|
|
15
|
+
try {
|
|
16
|
+
items = await profile.portfolio.remove(token, id);
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
handlePortfolioError("portfolio remove", err, format);
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
emitMutationResult(items, format, "remove", { id, prettyHeader: id });
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=remove.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remove.js","sourceRoot":"","sources":["../../../../src/commands/profile/portfolio/remove.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,oCAAoC;AAEpC,OAAO,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAGtC,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,UAAU,CAAC;AACpE,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,yBAAyB,CAAC,EAAU,EAAE,MAAoB;IAC9E,MAAM,KAAK,GAAG,MAAM,mBAAmB,CAAC,kBAAkB,EAAE,MAAM,CAAC,CAAC;IAEpE,IAAI,KAAwC,CAAC;IAC7C,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,oBAAoB,CAAC,kBAAkB,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC;QACtD,OAAO;IACT,CAAC;IAED,kBAAkB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,EAAE,EAAE,CAAC,CAAC;AACxE,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { OutputFormat } from "../../../lib/output.js";
|
|
2
|
+
/**
|
|
3
|
+
* Action handler for `ttctl profile portfolio reorder <id>`. The user
|
|
4
|
+
* supplies exactly one of `--before <id>` / `--after <id>` / `--to <pos>`;
|
|
5
|
+
* the helper translates `--before`/`--after` to an absolute position by
|
|
6
|
+
* fetching the current list, then issues `changePortfolioItemPosition`.
|
|
7
|
+
*
|
|
8
|
+
* Mutually-exclusive enforcement is at the CLI layer — the service-side
|
|
9
|
+
* `reorder()` only accepts an absolute integer position.
|
|
10
|
+
*/
|
|
11
|
+
export declare function runProfilePortfolioReorder(id: string, options: {
|
|
12
|
+
before?: string;
|
|
13
|
+
after?: string;
|
|
14
|
+
to?: string;
|
|
15
|
+
output: OutputFormat;
|
|
16
|
+
}): Promise<void>;
|
|
17
|
+
//# sourceMappingURL=reorder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reorder.d.ts","sourceRoot":"","sources":["../../../../src/commands/profile/portfolio/reorder.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,wBAAwB,CAAC;AAI3D;;;;;;;;GAQG;AACH,wBAAsB,0BAA0B,CAC9C,EAAE,EAAE,MAAM,EACV,OAAO,EAAE;IAAE,MAAM,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,YAAY,CAAA;CAAE,GAC9E,OAAO,CAAC,IAAI,CAAC,CAsHf"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
// SPDX-License-Identifier: AGPL-3.0-only
|
|
2
|
+
// Copyright (C) 2026 Oleksii PELYKH
|
|
3
|
+
import { profile } from "@ttctl/core";
|
|
4
|
+
import { emitErrorAndExit } from "../../../lib/envelopes.js";
|
|
5
|
+
import { emitMutationResult, handlePortfolioError } from "./add.js";
|
|
6
|
+
import { loadAuthTokenOrExit } from "./shared.js";
|
|
7
|
+
/**
|
|
8
|
+
* Action handler for `ttctl profile portfolio reorder <id>`. The user
|
|
9
|
+
* supplies exactly one of `--before <id>` / `--after <id>` / `--to <pos>`;
|
|
10
|
+
* the helper translates `--before`/`--after` to an absolute position by
|
|
11
|
+
* fetching the current list, then issues `changePortfolioItemPosition`.
|
|
12
|
+
*
|
|
13
|
+
* Mutually-exclusive enforcement is at the CLI layer — the service-side
|
|
14
|
+
* `reorder()` only accepts an absolute integer position.
|
|
15
|
+
*/
|
|
16
|
+
export async function runProfilePortfolioReorder(id, options) {
|
|
17
|
+
const modes = [options.before !== undefined, options.after !== undefined, options.to !== undefined];
|
|
18
|
+
const modeCount = modes.filter(Boolean).length;
|
|
19
|
+
if (modeCount === 0) {
|
|
20
|
+
emitErrorAndExit({
|
|
21
|
+
operation: "profile.portfolio.reorder",
|
|
22
|
+
format: options.output,
|
|
23
|
+
errors: [
|
|
24
|
+
{
|
|
25
|
+
code: "VALIDATION_ERROR",
|
|
26
|
+
message: "supply exactly one of --before <id>, --after <id>, or --to <position>.",
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
prettySummary: "portfolio reorder failed (VALIDATION_ERROR): supply exactly one of --before <id>, --after <id>, or --to <position>.",
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
if (modeCount > 1) {
|
|
33
|
+
emitErrorAndExit({
|
|
34
|
+
operation: "profile.portfolio.reorder",
|
|
35
|
+
format: options.output,
|
|
36
|
+
errors: [
|
|
37
|
+
{
|
|
38
|
+
code: "VALIDATION_ERROR",
|
|
39
|
+
message: "--before, --after, and --to are mutually exclusive.",
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
prettySummary: "portfolio reorder failed (VALIDATION_ERROR): --before, --after, and --to are mutually exclusive.",
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
const token = await loadAuthTokenOrExit("portfolio reorder", options.output);
|
|
46
|
+
let position;
|
|
47
|
+
if (options.to !== undefined) {
|
|
48
|
+
const parsed = Number.parseInt(options.to, 10);
|
|
49
|
+
if (!Number.isInteger(parsed) || parsed < 0) {
|
|
50
|
+
emitErrorAndExit({
|
|
51
|
+
operation: "profile.portfolio.reorder",
|
|
52
|
+
format: options.output,
|
|
53
|
+
errors: [
|
|
54
|
+
{
|
|
55
|
+
code: "VALIDATION_ERROR",
|
|
56
|
+
field: "to",
|
|
57
|
+
message: "--to must be a non-negative integer position.",
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
prettySummary: "portfolio reorder failed (VALIDATION_ERROR): --to must be a non-negative integer position.",
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
position = parsed;
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
// Need the current list to translate neighbour-anchored flags into
|
|
67
|
+
// an absolute index. The read is a separate round-trip; the cost
|
|
68
|
+
// is acceptable because reorder is a low-frequency operation.
|
|
69
|
+
let current;
|
|
70
|
+
try {
|
|
71
|
+
current = await profile.portfolio.list(token);
|
|
72
|
+
}
|
|
73
|
+
catch (err) {
|
|
74
|
+
handlePortfolioError("portfolio reorder", err, options.output);
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
if (options.before !== undefined) {
|
|
78
|
+
// Pass `id` (the moving item) so the helper filters it out before
|
|
79
|
+
// computing the target's index. Without it, the helper would
|
|
80
|
+
// return a position that's one off in the common "A before B (A
|
|
81
|
+
// is before B in the list)" case and the server would either
|
|
82
|
+
// reject or move the item to the wrong slot. See service-layer
|
|
83
|
+
// doc comment on `positionBefore` for the post-removal semantics.
|
|
84
|
+
const result = profile.portfolio.positionBefore(current, options.before, id);
|
|
85
|
+
if (result === null) {
|
|
86
|
+
emitErrorAndExit({
|
|
87
|
+
operation: "profile.portfolio.reorder",
|
|
88
|
+
format: options.output,
|
|
89
|
+
errors: [
|
|
90
|
+
{
|
|
91
|
+
code: "VALIDATION_ERROR",
|
|
92
|
+
field: "before",
|
|
93
|
+
message: `--before id '${options.before}' is not in the portfolio.`,
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
prettySummary: `portfolio reorder failed (VALIDATION_ERROR): --before id '${options.before}' is not in the portfolio.`,
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
position = result;
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
const after = options.after;
|
|
103
|
+
// See positionBefore comment above — `id` (moving item) is
|
|
104
|
+
// filtered out before computing the target's index.
|
|
105
|
+
const result = profile.portfolio.positionAfter(current, after, id);
|
|
106
|
+
if (result === null) {
|
|
107
|
+
emitErrorAndExit({
|
|
108
|
+
operation: "profile.portfolio.reorder",
|
|
109
|
+
format: options.output,
|
|
110
|
+
errors: [
|
|
111
|
+
{
|
|
112
|
+
code: "VALIDATION_ERROR",
|
|
113
|
+
field: "after",
|
|
114
|
+
message: `--after id '${after}' is not in the portfolio.`,
|
|
115
|
+
},
|
|
116
|
+
],
|
|
117
|
+
prettySummary: `portfolio reorder failed (VALIDATION_ERROR): --after id '${after}' is not in the portfolio.`,
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
position = result;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
let items;
|
|
124
|
+
try {
|
|
125
|
+
items = await profile.portfolio.reorder(token, id, position);
|
|
126
|
+
}
|
|
127
|
+
catch (err) {
|
|
128
|
+
handlePortfolioError("portfolio reorder", err, options.output);
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
emitMutationResult(items, options.output, "update", {
|
|
132
|
+
prettyHeader: `Portfolio item ${id} moved to position ${position.toString()}.`,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=reorder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reorder.js","sourceRoot":"","sources":["../../../../src/commands/profile/portfolio/reorder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared helpers for `ttctl profile portfolio` leaves. Re-exports
|
|
3
|
+
* `loadAuthTokenOrExit` from `../shared.ts` (post-#107 unification — the
|
|
4
|
+
* separate token file is gone; auth-token resolution is centralised on
|
|
5
|
+
* the in-memory `config.auth.token`).
|
|
6
|
+
*/
|
|
7
|
+
export { loadAuthTokenOrExit } from "../shared.js";
|
|
8
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../../../src/commands/profile/portfolio/shared.ts"],"names":[],"mappings":"AAGA;;;;;GAKG;AAEH,OAAO,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC"}
|