ptn 0.2.5__py3-none-any.whl → 0.4.2__py3-none-any.whl
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.
- porterminal/__init__.py +63 -11
- porterminal/_version.py +2 -2
- porterminal/app.py +25 -1
- porterminal/application/ports/__init__.py +2 -0
- porterminal/application/ports/connection_registry_port.py +46 -0
- porterminal/application/services/management_service.py +30 -55
- porterminal/application/services/session_service.py +3 -11
- porterminal/application/services/terminal_service.py +97 -56
- porterminal/cli/args.py +91 -30
- porterminal/cli/display.py +18 -16
- porterminal/cli/script_discovery.py +112 -0
- porterminal/composition.py +8 -7
- porterminal/config.py +12 -2
- porterminal/container.py +4 -0
- porterminal/domain/__init__.py +0 -9
- porterminal/domain/entities/output_buffer.py +56 -1
- porterminal/domain/entities/tab.py +11 -10
- porterminal/domain/services/__init__.py +0 -2
- porterminal/domain/values/__init__.py +0 -4
- porterminal/domain/values/environment_rules.py +3 -0
- porterminal/infrastructure/auth.py +131 -0
- porterminal/infrastructure/cloudflared.py +18 -12
- porterminal/infrastructure/config/shell_detector.py +407 -1
- porterminal/infrastructure/repositories/in_memory_session.py +1 -4
- porterminal/infrastructure/repositories/in_memory_tab.py +2 -10
- porterminal/infrastructure/server.py +28 -3
- porterminal/pty/env.py +16 -78
- porterminal/pty/manager.py +6 -4
- porterminal/static/assets/app-DlWNJWFE.js +87 -0
- porterminal/static/assets/app-xPAM7YhQ.css +1 -0
- porterminal/static/index.html +14 -2
- porterminal/updater.py +13 -5
- {ptn-0.2.5.dist-info → ptn-0.4.2.dist-info}/METADATA +84 -23
- {ptn-0.2.5.dist-info → ptn-0.4.2.dist-info}/RECORD +37 -34
- porterminal/static/assets/app-By4EXMHC.js +0 -72
- porterminal/static/assets/app-DQePboVd.css +0 -32
- {ptn-0.2.5.dist-info → ptn-0.4.2.dist-info}/WHEEL +0 -0
- {ptn-0.2.5.dist-info → ptn-0.4.2.dist-info}/entry_points.txt +0 -0
- {ptn-0.2.5.dist-info → ptn-0.4.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.xterm{cursor:text;position:relative;user-select:none;-ms-user-select:none;-webkit-user-select:none}.xterm.focus,.xterm:focus{outline:none}.xterm .xterm-helpers{position:absolute;top:0;z-index:5}.xterm .xterm-helper-textarea{padding:0;border:0;margin:0;position:absolute;opacity:0;left:-9999em;top:0;width:0;height:0;z-index:-5;white-space:nowrap;overflow:hidden;resize:none}.xterm .composition-view{background:#000;color:#fff;display:none;position:absolute;white-space:nowrap;z-index:1}.xterm .composition-view.active{display:block}.xterm .xterm-viewport{background-color:#000;overflow-y:scroll;cursor:default;position:absolute;inset:0}.xterm .xterm-screen{position:relative}.xterm .xterm-screen canvas{position:absolute;left:0;top:0}.xterm-char-measure-element{display:inline-block;visibility:hidden;position:absolute;top:0;left:-9999em;line-height:normal}.xterm.enable-mouse-events{cursor:default}.xterm.xterm-cursor-pointer,.xterm .xterm-cursor-pointer{cursor:pointer}.xterm.column-select.focus{cursor:crosshair}.xterm .xterm-accessibility:not(.debug),.xterm .xterm-message{position:absolute;inset:0;z-index:10;color:transparent;pointer-events:none}.xterm .xterm-accessibility-tree:not(.debug) *::selection{color:transparent}.xterm .xterm-accessibility-tree{font-family:monospace;-webkit-user-select:text;user-select:text;white-space:pre}.xterm .xterm-accessibility-tree>div{transform-origin:left;width:fit-content}.xterm .live-region{position:absolute;left:-9999px;width:1px;height:1px;overflow:hidden}.xterm-dim{opacity:1!important}.xterm-underline-1{text-decoration:underline}.xterm-underline-2{text-decoration:double underline}.xterm-underline-3{text-decoration:wavy underline}.xterm-underline-4{text-decoration:dotted underline}.xterm-underline-5{text-decoration:dashed underline}.xterm-overline{text-decoration:overline}.xterm-overline.xterm-underline-1{text-decoration:overline underline}.xterm-overline.xterm-underline-2{text-decoration:overline double underline}.xterm-overline.xterm-underline-3{text-decoration:overline wavy underline}.xterm-overline.xterm-underline-4{text-decoration:overline dotted underline}.xterm-overline.xterm-underline-5{text-decoration:overline dashed underline}.xterm-strikethrough{text-decoration:line-through}.xterm-screen .xterm-decoration-container .xterm-decoration{z-index:6;position:absolute}.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer{z-index:7}.xterm-decoration-overview-ruler{z-index:8;position:absolute;top:0;right:0;pointer-events:none}.xterm-decoration-top{z-index:2;position:relative}.xterm .xterm-scrollable-element>.scrollbar{cursor:default}.xterm .xterm-scrollable-element>.scrollbar>.scra{cursor:pointer;font-size:11px!important}.xterm .xterm-scrollable-element>.visible{opacity:1;background:#0000;transition:opacity .1s linear;z-index:11}.xterm .xterm-scrollable-element>.invisible{opacity:0;pointer-events:none}.xterm .xterm-scrollable-element>.invisible.fade{transition:opacity .8s linear}.xterm .xterm-scrollable-element>.shadow{position:absolute;display:none}.xterm .xterm-scrollable-element>.shadow.top{display:block;top:0;left:3px;height:3px;width:100%;box-shadow:var(--vscode-scrollbar-shadow, #000) 0 6px 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.left{display:block;top:3px;left:0;height:100%;width:3px;box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}.xterm .xterm-scrollable-element>.shadow.top-left-corner{display:block;top:0;left:0;height:3px;width:3px}.xterm .xterm-scrollable-element>.shadow.top.left{box-shadow:var(--vscode-scrollbar-shadow, #000) 6px 0 6px -6px inset}*{box-sizing:border-box;-webkit-tap-highlight-color:transparent}:root{--row-height: 30px;--content-padding: 12px;--scrollbar-width: 8px;--transition-fast: .15s ease;--radius-sm: 4px;--radius-md: 6px;--radius-lg: 8px;--radius-xl: 12px;--bg-primary: #1e1e1e;--bg-elevated: #252525;--bg-surface: #2d2d2d;--bg-hover: #3a3a3a;--bg-gradient-top: #232323;--bg-gradient-bottom: #1a1a1a;--text-primary: #cccccc;--text-high: rgba(255, 255, 255, .9);--text-white: #fff;--text-secondary: rgba(255, 255, 255, .7);--text-muted: rgba(255, 255, 255, .5);--text-disabled: rgba(255, 255, 255, .4);--border-subtle: rgba(255, 255, 255, .05);--border-light: rgba(255, 255, 255, .1);--border-medium: rgba(255, 255, 255, .15);--border-active: rgba(255, 255, 255, .2);--color-success: rgba(100, 220, 100, .8);--color-success-text: rgba(130, 230, 150, 1);--color-success-bg: rgba(100, 200, 120, .15);--color-success-border: rgba(100, 200, 120, .3);--bg-success-gradient-top: #2a3a2a;--bg-success-gradient-bottom: #1f2f1f;--color-danger: rgba(255, 100, 100, .8);--color-danger-muted: rgba(255, 120, 120, .7);--color-danger-text: rgba(255, 150, 150, 1);--color-danger-bg: rgba(255, 80, 80, .15);--color-danger-border: rgba(255, 120, 120, .3);--bg-danger-gradient-top: #3a2a2a;--bg-danger-gradient-bottom: #2f1f1f;--color-accent: rgba(80, 160, 255, .8);--color-accent-text: rgba(150, 200, 255, 1);--color-accent-bg: rgba(80, 160, 255, .3);--color-accent-strong: rgba(80, 160, 255, .5);--color-locked: rgba(255, 160, 60, .8);--color-locked-bg: rgba(255, 160, 60, .5);--glow-locked: 0 0 8px rgba(255, 160, 60, .5);--color-tmux: rgba(0, 180, 0, .8);--color-tmux-text: rgba(100, 220, 100, 1);--color-tmux-bg: rgba(0, 180, 0, .15);--hover-overlay: rgba(255, 255, 255, .05);--active-overlay: rgba(255, 255, 255, .08);--scrollbar-thumb: rgba(255, 255, 255, .15);--scrollbar-hover: rgba(255, 255, 255, .25);--cursor-color: #aeafad;--selection-bg: rgba(38, 79, 120, .5);--shadow-elevated: 0 4px 16px rgba(0, 0, 0, .5);--glow-success: 0 0 6px rgba(100, 220, 100, .4);--glow-danger: 0 0 6px rgba(255, 100, 100, .4);--glow-accent: 0 0 8px rgba(80, 160, 255, .4);--overlay-bg: rgba(0, 0, 0, .9)}.tool-btn,.tab-btn{-webkit-touch-callout:none}html,body{margin:0;padding:0;height:100%;overflow:hidden;background:var(--bg-primary);color:var(--text-primary);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;font-size:13px;position:fixed;width:100%;touch-action:none;overscroll-behavior:none}#app{display:flex;flex-direction:column;height:100%;height:100dvh;height:100svh;padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px);overflow:hidden;overscroll-behavior:none}#tab-bar{display:flex;align-items:center;height:var(--row-height);min-height:var(--row-height);background:linear-gradient(to bottom,var(--bg-gradient-top),var(--bg-gradient-bottom));border-bottom:1px solid var(--border-subtle);overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}#tab-bar::-webkit-scrollbar{display:none}.tab-btn{display:flex;align-items:center;gap:2px;height:var(--row-height);padding:0 8px;background:transparent;border:none;border-right:1px solid var(--border-subtle);color:var(--text-muted);font-size:12px;cursor:pointer;white-space:nowrap;flex-shrink:0;transition:all var(--transition-fast)}.tab-btn:active{background:var(--hover-overlay)}.tab-btn.active{background:var(--active-overlay);color:var(--text-high)}.tab-btn.tab-add{color:var(--text-disabled);font-size:18px;padding:0 10px;border-right:none}.tab-btn.tab-add:active{color:var(--text-high)}.tab-label{max-width:100px;overflow:hidden;text-overflow:ellipsis}.tab-close{display:flex;align-items:center;justify-content:center;width:16px;height:16px;margin-left:2px;border-radius:var(--radius-sm);font-size:14px;color:var(--text-disabled);transition:all var(--transition-fast);position:relative;overflow:hidden}.tab-close:before{content:"";position:absolute;top:0;left:0;width:100%;height:100%;background:var(--color-danger-bg);transform:scaleX(0);transform-origin:left;transition:transform .4s ease-out;z-index:-1}.tab-close.holding:before{transform:scaleX(1)}.tab-close.holding{color:var(--color-danger-text)}.tab-close.ready{background:var(--color-danger-bg);color:var(--color-danger-text);animation:pulseReady .3s ease}@keyframes pulseReady{0%,to{transform:scale(1)}50%{transform:scale(1.1)}}#shell-selector{margin-left:auto;display:flex;align-items:center;padding:0 var(--content-padding);height:var(--row-height);border-left:1px solid var(--border-subtle)}#shell-select{background:transparent;border:none;color:var(--text-secondary);font-size:11px;padding:4px 8px;cursor:pointer;-webkit-appearance:none;appearance:none}#connection-dot{width:6px;height:6px;border-radius:50%;background:var(--color-danger);margin-left:var(--content-padding);margin-right:8px;box-shadow:var(--glow-danger);flex-shrink:0}#connection-dot.connected{background:var(--color-success);box-shadow:var(--glow-success)}#btn-info,#btn-textview,#btn-shutdown{background:transparent;border:none;color:var(--text-disabled);font-size:14px;padding:4px;margin-left:4px;cursor:pointer;transition:color var(--transition-fast)}#btn-textview{padding:4px 0;margin-left:2px;margin-right:4px;font-size:11px;font-weight:500}#btn-info:active,#btn-textview:active{color:var(--color-accent)}#btn-shutdown{color:var(--color-danger-muted)}#btn-shutdown:active{color:var(--color-danger-text)}#terminal-container{flex:1;overflow:hidden;background:var(--bg-primary);padding:0 0 0 var(--content-padding);-webkit-user-select:none;user-select:none;-webkit-touch-callout:none;touch-action:none;overscroll-behavior:contain;contain:strict;isolation:isolate}#terminal{height:100%!important;contain:layout paint}.terminal-instance{height:100%;width:100%;contain:layout paint}.xterm-screen canvas,.xterm canvas{transform:translateZ(0);backface-visibility:hidden}#terminal .xterm-viewport{background:var(--bg-primary)!important;overflow-y:overlay!important;touch-action:none;overscroll-behavior:contain;contain:paint}#terminal .xterm-viewport::-webkit-scrollbar{width:var(--scrollbar-width)}#terminal .xterm-viewport::-webkit-scrollbar-track{background:transparent}#terminal .xterm-viewport::-webkit-scrollbar-thumb{background:var(--scrollbar-thumb);border-radius:var(--radius-sm)}#terminal .xterm-viewport::-webkit-scrollbar-thumb:hover{background:var(--scrollbar-hover)}#terminal .xterm-screen{-webkit-user-select:none;user-select:none;-webkit-touch-callout:none}#terminal .xterm-helper-textarea,.xterm-helper-textarea{-webkit-text-security:none!important;font-size:16px!important;-webkit-user-select:text;user-select:text}.xterm-helper-textarea::-webkit-contacts-auto-fill-button,.xterm-helper-textarea::-webkit-credentials-auto-fill-button{visibility:hidden;display:none!important;pointer-events:none;position:absolute;right:0;width:0;height:0}#toolbar{display:flex;flex-direction:column;background:linear-gradient(to bottom,var(--bg-gradient-top),var(--bg-gradient-bottom));border-top:1px solid var(--border-subtle);padding-bottom:env(safe-area-inset-bottom,0px)}.toolbar-row{display:flex;align-items:center;justify-content:center;height:var(--row-height);min-height:var(--row-height);gap:0;overflow-x:auto;overflow-y:hidden;scrollbar-width:none;-ms-overflow-style:none}.toolbar-row:first-child{border-bottom:1px solid var(--border-subtle)}.toolbar-row::-webkit-scrollbar{display:none}.tool-btn{display:flex;align-items:center;justify-content:center;height:var(--row-height);padding:0 10px;background:transparent;border:none;border-right:1px solid var(--border-subtle);border-radius:0;color:var(--text-muted);font-size:12px;cursor:pointer;transition:all var(--transition-fast);-webkit-touch-callout:none;flex-shrink:0}.tool-btn:active{background:var(--hover-overlay);color:var(--text-high)}.tool-btn.arrow{padding:0 10px}.tool-btn.danger{color:var(--color-danger-muted)}.tool-btn.danger:active{background:var(--color-danger-bg);color:var(--color-danger-text)}.tool-btn.tmux{color:var(--color-tmux)}.tool-btn.tmux:active{background:var(--color-tmux-bg);color:var(--color-tmux-text)}.tool-btn.modifier{padding:0 10px}.tool-btn.icon{font-size:18px}.tool-btn.enter{color:var(--color-success)}.tool-btn.enter:active{background:var(--color-success-bg);color:var(--color-success-text)}.tool-btn.sticky{background:var(--color-accent-bg);color:var(--color-accent-text)}.tool-btn.locked{background:var(--color-locked-bg);color:var(--text-white);box-shadow:var(--glow-locked)}#disconnect-overlay{position:fixed;inset:0;background:var(--overlay-bg);z-index:1000;display:flex;align-items:center;justify-content:center}#disconnect-content{text-align:center}#disconnect-icon{font-size:48px;color:var(--color-danger);margin-bottom:16px}#disconnect-text{color:var(--text-secondary);font-size:18px;margin-bottom:24px}#disconnect-retry{padding:var(--content-padding) 32px;background:var(--border-light);border:1px solid var(--border-medium);border-radius:var(--radius-lg);color:var(--text-high);font-size:14px;cursor:pointer;transition:all var(--transition-fast)}#disconnect-retry:active{background:var(--border-active);color:var(--text-white)}#auth-overlay{position:fixed;inset:0;background:var(--overlay-bg);z-index:1001;display:flex;align-items:center;justify-content:center;padding:20px}#auth-content{background:var(--bg-elevated);border:1px solid var(--border-light);border-radius:0;max-width:320px;width:100%;box-shadow:var(--shadow-elevated);animation:helpAppear var(--transition-fast)}#auth-header{display:flex;align-items:center;justify-content:center;padding:var(--content-padding) 16px;border-bottom:1px solid var(--border-subtle);color:var(--text-high);font-size:14px;font-weight:500}#auth-body{padding:var(--content-padding) 16px;display:flex;flex-direction:column;gap:12px}#auth-error{padding:8px 12px;background:var(--color-danger-bg);border:1px solid var(--color-danger-border);border-radius:0;color:var(--color-danger-text);font-size:12px;text-align:center}#auth-password{padding:10px 12px;background:var(--bg-surface);border:1px solid var(--border-medium);border-radius:0;color:var(--text-high);font-size:14px;outline:none;transition:border-color var(--transition-fast)}#auth-password:focus{border-color:var(--color-accent)}#auth-password::placeholder{color:var(--text-disabled)}#auth-submit{padding:var(--content-padding) 16px;background:var(--color-accent-bg);border:1px solid var(--color-accent);border-radius:0;color:var(--color-accent-text);font-size:14px;cursor:pointer;transition:all var(--transition-fast)}#auth-submit:active{background:var(--color-accent-strong);color:var(--text-white)}#auth-submit:disabled{opacity:.5;cursor:not-allowed}#copy-button{position:fixed;top:50%;left:50%;transform:translate(-50%,-50%);padding:8px 20px;background:linear-gradient(to bottom,var(--bg-surface),var(--bg-elevated));border:1px solid var(--border-light);border-radius:var(--radius-md);color:var(--text-high);font-family:-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;font-size:13px;font-weight:500;cursor:pointer;z-index:10000;box-shadow:var(--shadow-elevated);display:none;-webkit-tap-highlight-color:transparent;-webkit-touch-callout:none;touch-action:manipulation;transition:all var(--transition-fast)}#copy-button:active{background:linear-gradient(to bottom,var(--bg-hover),var(--bg-surface));transform:translate(-50%,-50%) scale(.97)}#copy-button.visible{display:block;animation:copyButtonAppear .1s ease-out}#copy-button.success{background:linear-gradient(to bottom,var(--bg-success-gradient-top),var(--bg-success-gradient-bottom));border-color:var(--color-success-border);color:var(--color-success-text)}#copy-button.error{background:linear-gradient(to bottom,var(--bg-danger-gradient-top),var(--bg-danger-gradient-bottom));border-color:var(--color-danger-border);color:var(--color-danger-text)}@keyframes copyButtonAppear{0%{opacity:0;transform:translate(-50%,-50%) scale(.9)}to{opacity:1;transform:translate(-50%,-50%) scale(1)}}#help-overlay{position:fixed;inset:0;background:var(--overlay-bg);z-index:1000;display:flex;align-items:center;justify-content:center;padding:20px}#help-content{background:var(--bg-elevated);border:1px solid var(--border-light);border-radius:var(--radius-xl);max-width:320px;width:100%;box-shadow:var(--shadow-elevated);animation:helpAppear var(--transition-fast)}@keyframes helpAppear{0%{opacity:0;transform:scale(.95)}to{opacity:1;transform:scale(1)}}#help-header{display:flex;align-items:center;justify-content:space-between;padding:var(--content-padding) 16px;border-bottom:1px solid var(--border-subtle);color:var(--text-high);font-size:14px;font-weight:500}#help-close{background:transparent;border:none;color:var(--text-muted);font-size:20px;cursor:pointer;padding:4px 8px;line-height:1}#help-close:active{color:var(--text-high)}#help-body{padding:var(--content-padding) 16px}.help-section{margin-bottom:var(--content-padding)}.help-section:last-child{margin-bottom:0}.help-title{color:var(--text-muted);font-size:10px;text-transform:uppercase;letter-spacing:.5px;margin-bottom:6px}.help-item{display:flex;align-items:center;gap:10px;padding:4px 0;color:var(--text-secondary);font-size:12px}.help-key{display:inline-block;min-width:80px;padding:2px 6px;background:var(--bg-surface);border:1px solid var(--border-subtle);border-radius:var(--radius-sm);color:var(--text-high);font-size:11px;text-align:center}#textview-overlay{position:fixed;inset:0;background:var(--bg-primary);z-index:1000;display:flex;flex-direction:column;padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px)}#textview-content{display:flex;flex-direction:column;width:100%;height:100%;background:var(--bg-primary)}#textview-header{display:flex;align-items:center;height:var(--row-height);min-height:var(--row-height);background:linear-gradient(to bottom,var(--bg-gradient-top),var(--bg-gradient-bottom));border-bottom:1px solid var(--border-subtle);flex-shrink:0}#textview-title{padding:0 var(--content-padding);color:var(--text-muted);font-size:12px;border-right:1px solid var(--border-subtle)}.textview-zoom-btn{display:flex;align-items:center;justify-content:center;height:var(--row-height);padding:0 var(--content-padding);background:transparent;border:none;border-right:1px solid var(--border-subtle);color:var(--text-muted);font-size:14px;cursor:pointer;transition:all var(--transition-fast)}.textview-zoom-btn:active{background:var(--hover-overlay);color:var(--text-high)}#textview-close{margin-left:auto;display:flex;align-items:center;justify-content:center;height:var(--row-height);padding:0 var(--content-padding);background:transparent;border:none;border-left:1px solid var(--border-subtle);color:var(--text-muted);font-size:16px;cursor:pointer;transition:all var(--transition-fast)}#textview-close:active{background:var(--hover-overlay);color:var(--text-high)}#textview-body{flex:1;min-height:0;margin:0;padding:8px var(--content-padding);background:var(--bg-primary);border:none;color:var(--text-primary);font-family:Menlo,Monaco,Consolas,monospace;font-size:9px;line-height:1.3;overflow-y:auto;white-space:pre-wrap;word-wrap:break-word;user-select:text;-webkit-user-select:text}.hidden{display:none!important}@media(prefers-reduced-motion:reduce){*,*:before,*:after{animation-duration:.01ms!important;transition-duration:.01ms!important}}
|
porterminal/static/index.html
CHANGED
|
@@ -16,8 +16,8 @@
|
|
|
16
16
|
|
|
17
17
|
<!-- Icons (PWA disabled - not useful for tunnel-based access) -->
|
|
18
18
|
<link rel="icon" type="image/svg+xml" href="/static/icon.svg">
|
|
19
|
-
<script type="module" crossorigin src="/static/assets/app-
|
|
20
|
-
<link rel="stylesheet" crossorigin href="/static/assets/app-
|
|
19
|
+
<script type="module" crossorigin src="/static/assets/app-DlWNJWFE.js"></script>
|
|
20
|
+
<link rel="stylesheet" crossorigin href="/static/assets/app-xPAM7YhQ.css">
|
|
21
21
|
</head>
|
|
22
22
|
<body>
|
|
23
23
|
<div id="app">
|
|
@@ -126,5 +126,17 @@
|
|
|
126
126
|
</div>
|
|
127
127
|
</div>
|
|
128
128
|
|
|
129
|
+
<!-- Auth Overlay -->
|
|
130
|
+
<div id="auth-overlay" class="hidden">
|
|
131
|
+
<div id="auth-content">
|
|
132
|
+
<div id="auth-header">Authentication Required</div>
|
|
133
|
+
<div id="auth-body">
|
|
134
|
+
<div id="auth-error" class="hidden"></div>
|
|
135
|
+
<input type="password" id="auth-password" placeholder="Enter password" autocomplete="current-password">
|
|
136
|
+
<button id="auth-submit">Connect</button>
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
|
|
129
141
|
</body>
|
|
130
142
|
</html>
|
porterminal/updater.py
CHANGED
|
@@ -34,6 +34,12 @@ def _detect_install_method() -> str:
|
|
|
34
34
|
return "pip"
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
def _parse_version(v: str) -> tuple[int, ...]:
|
|
38
|
+
"""Parse version string to comparable tuple."""
|
|
39
|
+
v = v.lstrip("v").split("+")[0].split(".dev")[0]
|
|
40
|
+
return tuple(int(p) for p in v.split(".")[:3] if p.isdigit())
|
|
41
|
+
|
|
42
|
+
|
|
37
43
|
def _is_newer(latest: str, current: str) -> bool:
|
|
38
44
|
"""Return True if latest > current."""
|
|
39
45
|
try:
|
|
@@ -42,12 +48,8 @@ def _is_newer(latest: str, current: str) -> bool:
|
|
|
42
48
|
return Version(latest) > Version(current)
|
|
43
49
|
except Exception:
|
|
44
50
|
# Fallback: tuple comparison (handles 0.9 vs 0.10 correctly)
|
|
45
|
-
def to_tuple(v: str) -> tuple[int, ...]:
|
|
46
|
-
v = v.lstrip("v").split("+")[0].split(".dev")[0]
|
|
47
|
-
return tuple(int(p) for p in v.split(".")[:3] if p.isdigit())
|
|
48
|
-
|
|
49
51
|
try:
|
|
50
|
-
return
|
|
52
|
+
return _parse_version(latest) > _parse_version(current)
|
|
51
53
|
except ValueError:
|
|
52
54
|
return False
|
|
53
55
|
|
|
@@ -154,6 +156,12 @@ def update_package() -> bool:
|
|
|
154
156
|
|
|
155
157
|
print(f"Updating {PACKAGE_NAME} {__version__} -> {latest}")
|
|
156
158
|
|
|
159
|
+
# Windows: can't upgrade while running (exe is locked)
|
|
160
|
+
if sys.platform == "win32":
|
|
161
|
+
print("On Windows, close ptn first then run from another terminal:")
|
|
162
|
+
print(f" {get_upgrade_command()}")
|
|
163
|
+
return False
|
|
164
|
+
|
|
157
165
|
method = _detect_install_method()
|
|
158
166
|
|
|
159
167
|
# Build command
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ptn
|
|
3
|
-
Version: 0.2
|
|
3
|
+
Version: 0.4.2
|
|
4
4
|
Summary: Web-based terminal accessible from phone via Cloudflare Tunnel
|
|
5
5
|
Project-URL: Homepage, https://github.com/lyehe/porterminal
|
|
6
6
|
Project-URL: Repository, https://github.com/lyehe/porterminal
|
|
@@ -26,6 +26,7 @@ Classifier: Topic :: Internet :: WWW/HTTP
|
|
|
26
26
|
Classifier: Topic :: System :: Shells
|
|
27
27
|
Classifier: Topic :: Terminals :: Terminal Emulators/X Terminals
|
|
28
28
|
Requires-Python: >=3.12
|
|
29
|
+
Requires-Dist: bcrypt>=4.0.0
|
|
29
30
|
Requires-Dist: fastapi>=0.104.0
|
|
30
31
|
Requires-Dist: pydantic>=2.0
|
|
31
32
|
Requires-Dist: pywinpty>=2.0.0; sys_platform == 'win32'
|
|
@@ -47,7 +48,7 @@ Description-Content-Type: text/markdown
|
|
|
47
48
|
<a href="https://pypi.org/project/ptn/"><img src="https://img.shields.io/pypi/v/ptn?style=flat-square&logo=pypi&logoColor=white&label=PyPI" alt="PyPI"></a>
|
|
48
49
|
<a href="https://pypi.org/project/ptn/"><img src="https://img.shields.io/pypi/pyversions/ptn?style=flat-square&logo=python&logoColor=white" alt="Python"></a>
|
|
49
50
|
<a href="https://pypi.org/project/ptn/"><img src="https://img.shields.io/pypi/dm/ptn?style=flat-square&label=Downloads" alt="Downloads"></a>
|
|
50
|
-
<a href="https://github.com/lyehe/porterminal/blob/
|
|
51
|
+
<a href="https://github.com/lyehe/porterminal/blob/master/LICENSE"><img src="https://img.shields.io/github/license/lyehe/porterminal?style=flat-square" alt="License"></a>
|
|
51
52
|
<a href="https://github.com/lyehe/porterminal/actions/workflows/ci.yml"><img src="https://img.shields.io/github/actions/workflow/status/lyehe/porterminal/ci.yml?branch=master&style=flat-square&logo=github&label=CI" alt="CI"></a>
|
|
52
53
|
</p>
|
|
53
54
|
|
|
@@ -60,22 +61,24 @@ Description-Content-Type: text/markdown
|
|
|
60
61
|
</p>
|
|
61
62
|
|
|
62
63
|
<p align="center">
|
|
63
|
-
<
|
|
64
|
+
<img src="assets/demo.gif" alt="Porterminal demo" width="320">
|
|
64
65
|
</p>
|
|
65
66
|
|
|
66
|
-
---
|
|
67
|
-
|
|
68
67
|
## Why
|
|
69
68
|
|
|
70
|
-
I wanted to vibe code from bed.
|
|
69
|
+
I wanted to vibe code from bed.
|
|
70
|
+
|
|
71
|
+
**ngrok** requires registration and the free tier sucks. **Cloudflare Quick Tunnel** works great but is hard to use directly on the phone. **Termius** requires complicated setup: port forwarding, firewall rules, key management... Tried **Claude Code web**, but it can't access my local hardware and environment. Also tried **Happy**, but it's too bulky and updates lag behind.
|
|
72
|
+
|
|
73
|
+
So I built something simpler: **run a command, scan a QR, start typing.**
|
|
71
74
|
|
|
72
75
|
## Features
|
|
73
76
|
|
|
74
77
|
- **One command, instant access** - No SSH, no port forwarding, no config files. Cloudflare tunnel + QR code.
|
|
75
|
-
- **Actually usable on mobile** -
|
|
76
|
-
- **
|
|
77
|
-
- **
|
|
78
|
-
- **
|
|
78
|
+
- **Actually usable on mobile** - Touch-optimized with momentum scrolling, pinch-to-zoom, swipe gestures, and modifier keys (Ctrl, Alt).
|
|
79
|
+
- **Full terminal apps** - vim, htop, less, tmux all work correctly with proper alt-screen buffer handling.
|
|
80
|
+
- **Persistent multi-tab sessions** - Sessions survive disconnects. Close the browser, switch networks, reconnect from another device—your shell and running processes are still there. Multiple devices can view the same session simultaneously.
|
|
81
|
+
- **Cross-platform** - Windows (PowerShell, CMD, WSL), Linux/macOS (Bash, Zsh, Fish, Nushell, and any shell via `$SHELL`). Auto-detects your shells.
|
|
79
82
|
|
|
80
83
|
## Install
|
|
81
84
|
|
|
@@ -86,6 +89,13 @@ I wanted to vibe code from bed. ngrok requires registration and the free tier su
|
|
|
86
89
|
| **pipx** | `pipx install ptn` | `pipx upgrade ptn` |
|
|
87
90
|
| **pip** | `pip install ptn` | `pip install -U ptn` |
|
|
88
91
|
|
|
92
|
+
**One-line install (uv + ptn):**
|
|
93
|
+
|
|
94
|
+
| OS | Command |
|
|
95
|
+
|----|---------|
|
|
96
|
+
| **Windows** | `powershell -ExecutionPolicy ByPass -c "irm https://raw.githubusercontent.com/lyehe/porterminal/master/install.ps1 \| iex"` |
|
|
97
|
+
| **macOS/Linux** | `curl -LsSf https://raw.githubusercontent.com/lyehe/porterminal/master/install.sh \| sh` |
|
|
98
|
+
|
|
89
99
|
Requires Python 3.12+ and [cloudflared](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/downloads/) (auto-installed if missing).
|
|
90
100
|
|
|
91
101
|
## Usage
|
|
@@ -93,44 +103,95 @@ Requires Python 3.12+ and [cloudflared](https://developers.cloudflare.com/cloudf
|
|
|
93
103
|
```bash
|
|
94
104
|
ptn # Start in current directory
|
|
95
105
|
ptn ~/projects/myapp # Start in specific folder
|
|
96
|
-
ptn --no-tunnel # Local network only
|
|
97
|
-
ptn -b # Run in background
|
|
98
|
-
ptn --init # Create .ptn/ptn.yaml config
|
|
99
|
-
ptn -U # Update to latest version
|
|
100
|
-
ptn --check-update # Check if update available
|
|
101
106
|
```
|
|
102
107
|
|
|
108
|
+
| Flag | Description |
|
|
109
|
+
|------|-------------|
|
|
110
|
+
| `-n, --no-tunnel` | Local network only (no Cloudflare tunnel) |
|
|
111
|
+
| `-b, --background` | Run in background and return immediately |
|
|
112
|
+
| `-p, --password` | Prompt for password to protect this session |
|
|
113
|
+
| `-dp, --default-password` | Toggle password requirement in config (on/off) |
|
|
114
|
+
| `-v, --verbose` | Show detailed startup logs |
|
|
115
|
+
| `-i, --init` | Create `.ptn/ptn.yaml` config with auto-discovered project scripts |
|
|
116
|
+
| `-u, --update` | Update to the latest version |
|
|
117
|
+
| `-c, --check-update` | Check if a newer version is available |
|
|
118
|
+
| `-V, --version` | Show version |
|
|
119
|
+
|
|
120
|
+
## Mobile Gestures
|
|
121
|
+
|
|
122
|
+
| Gesture | Action |
|
|
123
|
+
|---------|--------|
|
|
124
|
+
| **Tap** | Focus terminal, clear selection |
|
|
125
|
+
| **Long-press** | Start text selection |
|
|
126
|
+
| **Double-tap** | Select word |
|
|
127
|
+
| **Swipe left/right** | Arrow keys (← →) |
|
|
128
|
+
| **Scroll** | Momentum scrolling with physics |
|
|
129
|
+
| **Pinch** | Zoom text (10-24px) |
|
|
130
|
+
|
|
131
|
+
**Modifier keys** (Ctrl, Alt, Shift): Tap once for sticky (one keystroke), double-tap for lock.
|
|
132
|
+
|
|
103
133
|
## Configuration
|
|
104
134
|
|
|
105
|
-
Run `ptn --init` to create a starter config
|
|
135
|
+
Run `ptn --init` to create a starter config. It auto-discovers project scripts from `package.json`, `pyproject.toml`, or `Makefile` and adds them as buttons:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
ptn -i
|
|
139
|
+
# Created: .ptn/ptn.yaml
|
|
140
|
+
# Discovered 3 project script(s): build, dev, test
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
Or create `ptn.yaml` manually:
|
|
106
144
|
|
|
107
145
|
```yaml
|
|
146
|
+
# Terminal settings
|
|
147
|
+
terminal:
|
|
148
|
+
default_shell: nu # Default shell ID
|
|
149
|
+
shells: # Custom shell definitions
|
|
150
|
+
- id: nu
|
|
151
|
+
name: Nushell
|
|
152
|
+
command: nu
|
|
153
|
+
args: []
|
|
154
|
+
|
|
108
155
|
# Custom buttons (appear in toolbar)
|
|
156
|
+
# row: 1 = default row, 2+ = additional rows
|
|
109
157
|
buttons:
|
|
110
158
|
- label: "claude"
|
|
111
159
|
send:
|
|
112
160
|
- "claude"
|
|
113
161
|
- 100 # delay in ms
|
|
114
162
|
- "\r"
|
|
115
|
-
- label: "
|
|
116
|
-
send: "
|
|
163
|
+
- label: "build"
|
|
164
|
+
send: "npm run build\r"
|
|
165
|
+
row: 2 # second button row
|
|
117
166
|
|
|
118
167
|
# Update checker settings
|
|
119
168
|
update:
|
|
120
169
|
notify_on_startup: true # Show update notification
|
|
121
170
|
check_interval: 86400 # Seconds between checks (default: 24h)
|
|
171
|
+
|
|
172
|
+
# Security settings
|
|
173
|
+
security:
|
|
174
|
+
require_password: true # Always prompt for password at startup
|
|
175
|
+
max_auth_attempts: 5 # Max failed attempts before disconnect
|
|
122
176
|
```
|
|
123
177
|
|
|
124
178
|
Config is searched in order: `$PORTERMINAL_CONFIG_PATH`, `./ptn.yaml`, `./.ptn/ptn.yaml`, `~/.ptn/ptn.yaml`.
|
|
125
179
|
|
|
126
180
|
## Security
|
|
127
181
|
|
|
128
|
-
|
|
182
|
+
Use password if your screen can be exposed to others:
|
|
183
|
+
```bash
|
|
184
|
+
ptn -p # Prompt for password this session
|
|
185
|
+
ptn -dp # Enable password by default (toggle)
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Password is per-session (never saved to disk). See [docs/security.md](docs/security.md) for details.
|
|
189
|
+
|
|
190
|
+
## Troubleshooting
|
|
191
|
+
|
|
192
|
+
**Connection fails?** Cloudflare tunnel sometimes blocks connections. Restart the server (`Ctrl+C`, then `ptn`) to get a fresh tunnel URL.
|
|
129
193
|
|
|
130
|
-
|
|
131
|
-
- Stop the server when not in use (`Ctrl+C`)
|
|
132
|
-
- Use `--no-tunnel` for local network only
|
|
133
|
-
- Environment variables are sanitized (API keys, tokens stripped)
|
|
194
|
+
**Shell not detected?** Set your `$SHELL` environment variable or configure shells in `ptn.yaml`.
|
|
134
195
|
|
|
135
196
|
## Contributing
|
|
136
197
|
|
|
@@ -1,40 +1,42 @@
|
|
|
1
|
-
porterminal/__init__.py,sha256=
|
|
1
|
+
porterminal/__init__.py,sha256=aftLcHuDFp0nI5MF-eNyahFyx3nyGxf8SERK59-G_0Y,12604
|
|
2
2
|
porterminal/__main__.py,sha256=XLo21rqmISrIZFiaHC58Trgq8E0gxH4Wb3driD4JA7c,137
|
|
3
|
-
porterminal/_version.py,sha256=
|
|
4
|
-
porterminal/app.py,sha256=
|
|
3
|
+
porterminal/_version.py,sha256=A45grTqzrHuDn1CT9K5GVUbY4_Q3OSTcXAl3zdHzcEI,704
|
|
4
|
+
porterminal/app.py,sha256=Q3w-61i6h2Atz4wirAgrT--xTH_qCp4Ig2zgnAIyJ9U,15220
|
|
5
5
|
porterminal/asgi.py,sha256=P76H7k03T3GYBAmjWqLaCZXV-YIou6NMhfRySO8He1A,1276
|
|
6
|
-
porterminal/composition.py,sha256=
|
|
7
|
-
porterminal/config.py,sha256=
|
|
8
|
-
porterminal/container.py,sha256=
|
|
6
|
+
porterminal/composition.py,sha256=H1QJszJqGX4BXZE4cFk3I46yxybZPtNG35srqRi35vo,6799
|
|
7
|
+
porterminal/config.py,sha256=zt-Yy59U0o5DbFMcgBpTCw4rOEtywMD1mQpXDni9u5g,5687
|
|
8
|
+
porterminal/container.py,sha256=wDtppL1Xf4A6IQcP5FP-V9-hjKEDciQc4VMz5ezyv2o,1536
|
|
9
9
|
porterminal/logging_setup.py,sha256=DhoN_FdJFbRawcsYy8mLRU32TCT1ZfZ2G4Q_AOKwZuA,1513
|
|
10
|
-
porterminal/updater.py,sha256=
|
|
10
|
+
porterminal/updater.py,sha256=VqUL8NFOIL36dSeOFUs3TUAJP0u5D4toDFr1k1yi3Jg,6503
|
|
11
11
|
porterminal/application/__init__.py,sha256=Q5gQia_11ubfMcDbzjvI6RoUU2jFJkuQrsbSuIfQCRA,55
|
|
12
|
-
porterminal/application/ports/__init__.py,sha256=
|
|
12
|
+
porterminal/application/ports/__init__.py,sha256=bGZlGKTjKWWxiwNhjz47nA2K_wvFSp9dExNmo9Pikxg,240
|
|
13
13
|
porterminal/application/ports/connection_port.py,sha256=kXIl-fzx3SbpU8kV1rpmgNeI22XSJMbzXGt1YcwZO8Y,926
|
|
14
|
+
porterminal/application/ports/connection_registry_port.py,sha256=OAZMvcETGW4IkeJ2OPQ29wTEJ7HKBLj_pVlsnGY0znk,1386
|
|
14
15
|
porterminal/application/services/__init__.py,sha256=YO-iPdE_-EEV9tVnu0NcB5bwSCCSVy9CWOGBFCJyoRc,335
|
|
15
|
-
porterminal/application/services/management_service.py,sha256=
|
|
16
|
-
porterminal/application/services/session_service.py,sha256=
|
|
16
|
+
porterminal/application/services/management_service.py,sha256=nHNAlcgu2IoUZsNDmzvgEsh1j0sBMI8yDwg6BJk7r1Q,7933
|
|
17
|
+
porterminal/application/services/session_service.py,sha256=ng1B4GQOVBCjI6gqkb_cO_WDfmN3Lm_RUiyBYYkBzDk,7938
|
|
17
18
|
porterminal/application/services/tab_service.py,sha256=0_S978dYhBW2-eaZN2wOlcZOY4V4iPt2MMNOyoZQxPs,8307
|
|
18
|
-
porterminal/application/services/terminal_service.py,sha256=
|
|
19
|
+
porterminal/application/services/terminal_service.py,sha256=0zaQWgZ8Uz8JmDfTqww4p2rJfH6AIyG8dVmSH4JIp2I,22054
|
|
19
20
|
porterminal/cli/__init__.py,sha256=A3y-QgKrT-vdAYV-xsZjeyMkiPymZaZzYUGQ-_3cXmQ,305
|
|
20
|
-
porterminal/cli/args.py,sha256=
|
|
21
|
-
porterminal/cli/display.py,sha256=
|
|
22
|
-
porterminal/
|
|
21
|
+
porterminal/cli/args.py,sha256=ixXT4W3D6MjS3IemZNeEjyC0-Vfsf8kQGwHotpjJhXM,5970
|
|
22
|
+
porterminal/cli/display.py,sha256=PgLnRj9odMKYERMCLyrEhTrpYeYPNYC-a1nWcz_fFE0,5433
|
|
23
|
+
porterminal/cli/script_discovery.py,sha256=jdDRBZ-0LbtC2F1oV_oQtrd00duYWH2QXFs1FakKxtc,3869
|
|
24
|
+
porterminal/domain/__init__.py,sha256=16WEj1SAKhIqkrQHqaan66pV3zsUn1aEz7oymN54xFQ,1428
|
|
23
25
|
porterminal/domain/entities/__init__.py,sha256=dIQp6T0M-Bl_DJpSOGQGBD29Rl_FDR0XfVrDL08ck50,463
|
|
24
|
-
porterminal/domain/entities/output_buffer.py,sha256=
|
|
26
|
+
porterminal/domain/entities/output_buffer.py,sha256=TqqgGk3NEM_htNbAhZQCJM_dek4ajhwViPaVE3XXCeI,4220
|
|
25
27
|
porterminal/domain/entities/session.py,sha256=SzAEqbqr49QhcSW_2BqYVJst1_6yo8qs21Efh_uBJDA,2680
|
|
26
|
-
porterminal/domain/entities/tab.py,sha256=
|
|
28
|
+
porterminal/domain/entities/tab.py,sha256=YRh_4fWcRZFrFxtX-2awYfnglEOcWGBLc0baQc1Rffo,1996
|
|
27
29
|
porterminal/domain/ports/__init__.py,sha256=ryAYtrvSanQecroEz7tPHzWN_U9icx51Fn_snDBNDiQ,264
|
|
28
30
|
porterminal/domain/ports/pty_port.py,sha256=HGk7kyE1j5vG5aebB2XFfrhjNX6a2g37eUUPpgPJxu0,1179
|
|
29
31
|
porterminal/domain/ports/session_repository.py,sha256=Gh5c2cneboXYEuNw8Gxw06IZwpMqhN0HA7KINFFi2LQ,1611
|
|
30
32
|
porterminal/domain/ports/tab_repository.py,sha256=_QMuTqjc9A095sDInD4fk7sjCu_v-aXXM4HzCQsOyO0,1826
|
|
31
|
-
porterminal/domain/services/__init__.py,sha256=
|
|
33
|
+
porterminal/domain/services/__init__.py,sha256=eJYyrp1siHoxivk2eO9UGHucmnyFZbvQH01BjBAFv1I,477
|
|
32
34
|
porterminal/domain/services/environment_sanitizer.py,sha256=RslZDn8jso8bX1hG9p9NQyv1ey19u1F5xATPlq6pKVw,2014
|
|
33
35
|
porterminal/domain/services/rate_limiter.py,sha256=I0cybe1PX7uYWlr7l92N3jM89yFQDRKqD5p9-lT8Mas,1724
|
|
34
36
|
porterminal/domain/services/session_limits.py,sha256=EqW_tqr0Br3a2gzgl5Dg80dx1umcU6VMr4-ELRtGx_w,3181
|
|
35
37
|
porterminal/domain/services/tab_limits.py,sha256=nokX8gP9_41MNIdQ7Fri2JLAs4_Ch-fy3CgpKHTZnT8,1434
|
|
36
|
-
porterminal/domain/values/__init__.py,sha256=
|
|
37
|
-
porterminal/domain/values/environment_rules.py,sha256=
|
|
38
|
+
porterminal/domain/values/__init__.py,sha256=SuUiW8EINXgbpaCuqmdTGnVrmP0x2FuoJz3HsUzB7M0,516
|
|
39
|
+
porterminal/domain/values/environment_rules.py,sha256=ii3D3CP4v8V-4H13VadzE76Z8EyZdbx-h7CYnEvXmpw,3946
|
|
38
40
|
porterminal/domain/values/rate_limit_config.py,sha256=BZb-Jbxav8kJ6ijADIrW_-JhDt8WuPIe8OIqLnQykXA,548
|
|
39
41
|
porterminal/domain/values/session_id.py,sha256=dYBSZdG6WWjp06mUbTZwjufb30A6lSuK-NKwqxAAavY,461
|
|
40
42
|
porterminal/domain/values/shell_command.py,sha256=9U723nsdDCsW_M17qBp__cu3r9uuBVuur0kifaoiEF0,1102
|
|
@@ -42,30 +44,31 @@ porterminal/domain/values/tab_id.py,sha256=zKZZ1lBQUmXZ3PQlH0jejUQ_AA_SVTW-Z7jCI
|
|
|
42
44
|
porterminal/domain/values/terminal_dimensions.py,sha256=mWtMQi40EDtwnKpQadTR5eD0VmInO-2kgbUUw2VVCZY,1334
|
|
43
45
|
porterminal/domain/values/user_id.py,sha256=eskGRVL-qj4czXljF0e5imDh19pAq16faXJY0lZ73kM,581
|
|
44
46
|
porterminal/infrastructure/__init__.py,sha256=rIaiEG4gyvfSixSEry0kA2uMhStQQIWv9PRlfs17qts,649
|
|
45
|
-
porterminal/infrastructure/
|
|
47
|
+
porterminal/infrastructure/auth.py,sha256=vBXC9TJrydbQDadvYqfznhQ2YRZ2BGBseabJ-IAmUeA,3931
|
|
48
|
+
porterminal/infrastructure/cloudflared.py,sha256=E7VtcZv4U5HeO1t4JYAO-97JavlD811-lR5A8bwPyPI,11606
|
|
46
49
|
porterminal/infrastructure/network.py,sha256=XnYbEXKQA8BnrLFl9b4OTTixFG1pVFxfeVuhN-XPkfU,1275
|
|
47
|
-
porterminal/infrastructure/server.py,sha256=
|
|
50
|
+
porterminal/infrastructure/server.py,sha256=n6lSZjd6m380QzvdAZAu7CbbRoTvTAL8Dp-mcMaNFmY,5803
|
|
48
51
|
porterminal/infrastructure/config/__init__.py,sha256=kcoM8mQYa83rkxn8TUfh0nETKynrsLmVwD9ySIfvdPQ,139
|
|
49
|
-
porterminal/infrastructure/config/shell_detector.py,sha256=
|
|
52
|
+
porterminal/infrastructure/config/shell_detector.py,sha256=CPL7b7EgUcFNmjDzwzA-HxYCQNmyOzVw2xNGfmiQv_Q,16569
|
|
50
53
|
porterminal/infrastructure/registry/__init__.py,sha256=reNbIYRr1alNps7zm_oENuS6QWNKiiO-WG09LT5MLmM,157
|
|
51
54
|
porterminal/infrastructure/registry/user_connection_registry.py,sha256=u9KOSijHiRITnwnOBKwXuYOKbFguh2NbxmNMxIoo8vc,3398
|
|
52
55
|
porterminal/infrastructure/repositories/__init__.py,sha256=UyF9lpobXgKb9Ti6ucC6fDcC9CkMAGDThggEG-Rf-Aw,250
|
|
53
|
-
porterminal/infrastructure/repositories/in_memory_session.py,sha256=
|
|
54
|
-
porterminal/infrastructure/repositories/in_memory_tab.py,sha256=
|
|
56
|
+
porterminal/infrastructure/repositories/in_memory_session.py,sha256=PpnW16Hje5pvY_NHMxeWpVxmwjlSx0T4dxAsw5GcAcI,2411
|
|
57
|
+
porterminal/infrastructure/repositories/in_memory_tab.py,sha256=tXeZQkIHLcdR_p-zm5mR4g8AAhB6TQyrQJmc8k4Df4k,4025
|
|
55
58
|
porterminal/infrastructure/web/__init__.py,sha256=QZqOtxOqhuxh4AD5xzPl9CBfOscdXOoGQv4zT4rpy7Q,147
|
|
56
59
|
porterminal/infrastructure/web/websocket_adapter.py,sha256=vVjIhcfWikPw-PKfSyqm3Y7PbTxNj1mstfrHIpcg6ng,2424
|
|
57
60
|
porterminal/pty/__init__.py,sha256=WNniN5uYKthLMOT7nzH63pkfFCJltToika50NZGR2cA,1054
|
|
58
|
-
porterminal/pty/env.py,sha256
|
|
59
|
-
porterminal/pty/manager.py,sha256=
|
|
61
|
+
porterminal/pty/env.py,sha256=fr5H1wEFXPCZnHW5KzeI4B5rWB4ixeXcXdrlR_GzBsU,1048
|
|
62
|
+
porterminal/pty/manager.py,sha256=W-uaPWA4SmNl00OA4-FS05A8b0LoaYo0ANsxll0ypwU,4605
|
|
60
63
|
porterminal/pty/protocol.py,sha256=-OPHIfLxL6R_JTrOQNB2t-sRH7LqtFgJE3QkBcHBqNA,1982
|
|
61
64
|
porterminal/pty/unix.py,sha256=hDwHuD2XD4RN6t_Hk_q-XvgQ4dNF9zUSwJhe0-Y9JBU,5094
|
|
62
65
|
porterminal/pty/windows.py,sha256=7WrtxgUbqDKSPMK9_pN9vNPzMalV1p-UyyZlBZJn8EY,3933
|
|
63
66
|
porterminal/static/icon.svg,sha256=y7-MIl7F_wVQMLHWmmC7MrZHZK5ikLg1BR_0jbqnTkc,1949
|
|
64
|
-
porterminal/static/index.html,sha256=
|
|
65
|
-
porterminal/static/assets/app-
|
|
66
|
-
porterminal/static/assets/app-
|
|
67
|
-
ptn-0.2.
|
|
68
|
-
ptn-0.2.
|
|
69
|
-
ptn-0.2.
|
|
70
|
-
ptn-0.2.
|
|
71
|
-
ptn-0.2.
|
|
67
|
+
porterminal/static/index.html,sha256=xLfeiS_g9ujuJooN0QZWgt38q2ub1UcHs_anNS4ONgU,6401
|
|
68
|
+
porterminal/static/assets/app-DlWNJWFE.js,sha256=HxwLXBSp5CrSOMhaI6O0zHxBY3J8dQlW5IuC_L8LnoQ,486711
|
|
69
|
+
porterminal/static/assets/app-xPAM7YhQ.css,sha256=dYk-DAJSmvxP8fn5ABN5Jy_djhlpREDFjcIGKpb2gjw,18949
|
|
70
|
+
ptn-0.4.2.dist-info/METADATA,sha256=1Y7txZBGmjLeOs4MI_UR3FgWM0X_d_DBUj5Ln10mJtg,8124
|
|
71
|
+
ptn-0.4.2.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
72
|
+
ptn-0.4.2.dist-info/entry_points.txt,sha256=Ftj1zSu_7G0yD5mAtGN3RoewyIuoBOfP_noSISe73tU,41
|
|
73
|
+
ptn-0.4.2.dist-info/licenses/LICENSE,sha256=DZak_2itbUtvHzD3E7GNUYSRK6jdOJ-GqncQ2weavLA,34523
|
|
74
|
+
ptn-0.4.2.dist-info/RECORD,,
|