@hienlh/ppm 0.1.0 → 0.1.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/dist/web/assets/api-client-Bnf9LAt4.js +1 -0
- package/dist/web/assets/arrow-up-from-line-BXL5dtbG.js +1 -0
- package/dist/web/assets/button-BxijdhtM.js +1 -0
- package/dist/web/assets/chat-tab-BZopEuub.js +61 -0
- package/dist/web/assets/code-editor-hbllHzj7.js +2 -0
- package/dist/web/assets/createLucideIcon-Dy1wlrF7.js +1 -0
- package/dist/web/assets/dialog-RczsXsmw.js +45 -0
- package/dist/web/assets/diff-viewer-D6ixPlNB.js +4 -0
- package/dist/web/assets/dist-CSp7ir0r.js +46 -0
- package/dist/web/assets/external-link-WSiY-639.js +1 -0
- package/dist/web/assets/git-graph-DXMB_DoT.js +1 -0
- package/dist/web/assets/git-status-panel-D8ZUQrRF.js +1 -0
- package/dist/web/assets/index-DGSLw2GE.js +10 -0
- package/dist/web/assets/index-DYd_2slk.css +2 -0
- package/dist/web/assets/jsx-runtime-BnxRlLMJ.js +1 -0
- package/dist/web/assets/project-list-DWVXEimw.js +1 -0
- package/dist/web/assets/react-Uzd0zARU.js +1 -0
- package/dist/web/assets/refresh-cw-DtopuYJf.js +1 -0
- package/dist/web/assets/settings-tab-DJRzIAuP.js +1 -0
- package/dist/web/assets/terminal-tab-BrP-ENHg.css +1 -0
- package/dist/web/assets/terminal-tab-CbwaI-oq.js +36 -0
- package/dist/web/assets/trash-2-CHLebaNh.js +1 -0
- package/dist/web/assets/utils-Cgi2TYRi.js +1 -0
- package/dist/web/assets/x-BISR7bpK.js +1 -0
- package/dist/web/icon-192.svg +5 -0
- package/dist/web/icon-512.svg +5 -0
- package/dist/web/index.html +25 -0
- package/dist/web/manifest.webmanifest +1 -0
- package/dist/web/registerSW.js +1 -0
- package/dist/web/sw.js +1 -0
- package/dist/web/workbox-3e722498.js +1 -0
- package/package.json +2 -1
- package/src/server/index.ts +17 -3
- package/.claude/agent-memory/tester/MEMORY.md +0 -3
- package/.claude/agent-memory/tester/project-ppm-test-conventions.md +0 -32
- package/.github/workflows/release.yml +0 -46
- package/plans/260314-2009-ppm-implementation/phase-01-project-skeleton.md +0 -81
- package/plans/260314-2009-ppm-implementation/phase-02-backend-core.md +0 -148
- package/plans/260314-2009-ppm-implementation/phase-03-frontend-shell.md +0 -256
- package/plans/260314-2009-ppm-implementation/phase-04-file-explorer-editor.md +0 -120
- package/plans/260314-2009-ppm-implementation/phase-05-web-terminal.md +0 -174
- package/plans/260314-2009-ppm-implementation/phase-06-git-integration.md +0 -244
- package/plans/260314-2009-ppm-implementation/phase-07-ai-chat.md +0 -242
- package/plans/260314-2009-ppm-implementation/phase-08-cli-commands.md +0 -143
- package/plans/260314-2009-ppm-implementation/phase-09-pwa-build-deploy.md +0 -209
- package/plans/260314-2009-ppm-implementation/phase-10-testing.md +0 -311
- package/plans/260314-2009-ppm-implementation/plan.md +0 -202
- package/plans/260315-0356-project-scoped-api-refactor/phase-01-backend-project-router.md +0 -145
- package/plans/260315-0356-project-scoped-api-refactor/phase-02-frontend-api-migration.md +0 -107
- package/plans/260315-0356-project-scoped-api-refactor/phase-03-per-project-tabs.md +0 -100
- package/plans/260315-0356-project-scoped-api-refactor/phase-04-websocket-migration.md +0 -66
- package/plans/260315-0356-project-scoped-api-refactor/plan.md +0 -87
- package/plans/reports/brainstorm-260314-1938-final-techstack.md +0 -342
- package/plans/reports/docs-manager-260315-1314-documentation-creation.md +0 -386
- package/plans/reports/fullstack-developer-260314-2252-phase-02-backend-core.md +0 -57
- package/plans/reports/fullstack-developer-260314-2253-phase-03-frontend-shell.md +0 -70
- package/plans/reports/fullstack-developer-260314-2300-phase-04-05-file-api-terminal-ws.md +0 -49
- package/plans/reports/fullstack-developer-260314-2300-phase-04-05-file-explorer-editor-terminal.md +0 -52
- package/plans/reports/fullstack-developer-260314-2307-ai-chat-phase7.md +0 -58
- package/plans/reports/fullstack-developer-260314-2307-phase-06-git-integration.md +0 -33
- package/plans/reports/research-260314-1911-ppm-tech-stack.md +0 -318
- package/plans/reports/research-260314-1930-claude-code-integration.md +0 -293
- package/plans/reports/researcher-260314-2232-node-pty-bun-crash-analysis.md +0 -305
- package/plans/reports/researcher-260314-2232-ui-style.md +0 -942
- package/plans/reports/researcher-260315-0300-opcode-claude-interaction.md +0 -745
- package/plans/reports/researcher-260315-0303-opcode-deep-analysis.md +0 -742
- package/plans/reports/researcher-260315-0305-claude-agent-sdk-github-research.md +0 -423
- package/plans/reports/tester-260314-2053-initial-test-suite.md +0 -81
- package/repomix-output.xml +0 -23745
- package/tests/integration/api/chat-routes.test.ts +0 -95
- package/tests/integration/claude-agent-sdk-integration.test.ts +0 -228
- package/tests/integration/ws/chat-websocket.test.ts +0 -312
- package/tests/test-setup.ts +0 -5
- package/tests/unit/providers/claude-agent-sdk.test.ts +0 -339
- package/tests/unit/providers/mock-provider.test.ts +0 -143
- package/tests/unit/services/chat-service.test.ts +0 -100
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./createLucideIcon-Dy1wlrF7.js";var t=e(`trash-2`,[[`path`,{d:`M10 11v6`,key:`nco0om`}],[`path`,{d:`M14 11v6`,key:`outv1u`}],[`path`,{d:`M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6`,key:`miytrc`}],[`path`,{d:`M3 6h18`,key:`d0wm0j`}],[`path`,{d:`M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2`,key:`e791ji`}]]);export{t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function e(t){var n,r,i=``;if(typeof t==`string`||typeof t==`number`)i+=t;else if(typeof t==`object`)if(Array.isArray(t)){var a=t.length;for(n=0;n<a;n++)t[n]&&(r=e(t[n]))&&(i&&(i+=` `),i+=r)}else for(r in t)t[r]&&(i&&(i+=` `),i+=r);return i}function t(){for(var t,n,r=0,i=``,a=arguments.length;r<a;r++)(t=arguments[r])&&(n=e(t))&&(i&&(i+=` `),i+=n);return i}var n=(e,t)=>{let n=Array(e.length+t.length);for(let t=0;t<e.length;t++)n[t]=e[t];for(let r=0;r<t.length;r++)n[e.length+r]=t[r];return n},r=(e,t)=>({classGroupId:e,validator:t}),i=(e=new Map,t=null,n)=>({nextPart:e,validators:t,classGroupId:n}),a=`-`,o=[],s=`arbitrary..`,c=e=>{let t=ee(e),{conflictingClassGroups:r,conflictingClassGroupModifiers:i}=e;return{getClassGroupId:e=>{if(e.startsWith(`[`)&&e.endsWith(`]`))return u(e);let n=e.split(a);return l(n,n[0]===``&&n.length>1?1:0,t)},getConflictingClassGroupIds:(e,t)=>{if(t){let t=i[e],a=r[e];return t?a?n(a,t):t:a||o}return r[e]||o}}},l=(e,t,n)=>{if(e.length-t===0)return n.classGroupId;let r=e[t],i=n.nextPart.get(r);if(i){let n=l(e,t+1,i);if(n)return n}let o=n.validators;if(o===null)return;let s=t===0?e.join(a):e.slice(t).join(a),c=o.length;for(let e=0;e<c;e++){let t=o[e];if(t.validator(s))return t.classGroupId}},u=e=>e.slice(1,-1).indexOf(`:`)===-1?void 0:(()=>{let t=e.slice(1,-1),n=t.indexOf(`:`),r=t.slice(0,n);return r?s+r:void 0})(),ee=e=>{let{theme:t,classGroups:n}=e;return d(n,t)},d=(e,t)=>{let n=i();for(let r in e){let i=e[r];f(i,n,r,t)}return n},f=(e,t,n,r)=>{let i=e.length;for(let a=0;a<i;a++){let i=e[a];p(i,t,n,r)}},p=(e,t,n,r)=>{if(typeof e==`string`){m(e,t,n);return}if(typeof e==`function`){h(e,t,n,r);return}g(e,t,n,r)},m=(e,t,n)=>{let r=e===``?t:_(t,e);r.classGroupId=n},h=(e,t,n,i)=>{if(v(e)){f(e(i),t,n,i);return}t.validators===null&&(t.validators=[]),t.validators.push(r(n,e))},g=(e,t,n,r)=>{let i=Object.entries(e),a=i.length;for(let e=0;e<a;e++){let[a,o]=i[e];f(o,_(t,a),n,r)}},_=(e,t)=>{let n=e,r=t.split(a),o=r.length;for(let e=0;e<o;e++){let t=r[e],a=n.nextPart.get(t);a||(a=i(),n.nextPart.set(t,a)),n=a}return n},v=e=>`isThemeGetter`in e&&e.isThemeGetter===!0,y=e=>{if(e<1)return{get:()=>void 0,set:()=>{}};let t=0,n=Object.create(null),r=Object.create(null),i=(i,a)=>{n[i]=a,t++,t>e&&(t=0,r=n,n=Object.create(null))};return{get(e){let t=n[e];if(t!==void 0)return t;if((t=r[e])!==void 0)return i(e,t),t},set(e,t){e in n?n[e]=t:i(e,t)}}},b=`!`,x=`:`,S=[],C=(e,t,n,r,i)=>({modifiers:e,hasImportantModifier:t,baseClassName:n,maybePostfixModifierPosition:r,isExternal:i}),w=e=>{let{prefix:t,experimentalParseClassName:n}=e,r=e=>{let t=[],n=0,r=0,i=0,a,o=e.length;for(let s=0;s<o;s++){let o=e[s];if(n===0&&r===0){if(o===x){t.push(e.slice(i,s)),i=s+1;continue}if(o===`/`){a=s;continue}}o===`[`?n++:o===`]`?n--:o===`(`?r++:o===`)`&&r--}let s=t.length===0?e:e.slice(i),c=s,l=!1;s.endsWith(b)?(c=s.slice(0,-1),l=!0):s.startsWith(b)&&(c=s.slice(1),l=!0);let u=a&&a>i?a-i:void 0;return C(t,l,c,u)};if(t){let e=t+x,n=r;r=t=>t.startsWith(e)?n(t.slice(e.length)):C(S,!1,t,void 0,!0)}if(n){let e=r;r=t=>n({className:t,parseClassName:e})}return r},te=e=>{let t=new Map;return e.orderSensitiveModifiers.forEach((e,n)=>{t.set(e,1e6+n)}),e=>{let n=[],r=[];for(let i=0;i<e.length;i++){let a=e[i],o=a[0]===`[`,s=t.has(a);o||s?(r.length>0&&(r.sort(),n.push(...r),r=[]),n.push(a)):r.push(a)}return r.length>0&&(r.sort(),n.push(...r)),n}},ne=e=>({cache:y(e.cacheSize),parseClassName:w(e),sortModifiers:te(e),...c(e)}),T=/\s+/,re=(e,t)=>{let{parseClassName:n,getClassGroupId:r,getConflictingClassGroupIds:i,sortModifiers:a}=t,o=[],s=e.trim().split(T),c=``;for(let e=s.length-1;e>=0;--e){let t=s[e],{isExternal:l,modifiers:u,hasImportantModifier:ee,baseClassName:d,maybePostfixModifierPosition:f}=n(t);if(l){c=t+(c.length>0?` `+c:c);continue}let p=!!f,m=r(p?d.substring(0,f):d);if(!m){if(!p){c=t+(c.length>0?` `+c:c);continue}if(m=r(d),!m){c=t+(c.length>0?` `+c:c);continue}p=!1}let h=u.length===0?``:u.length===1?u[0]:a(u).join(`:`),g=ee?h+b:h,_=g+m;if(o.indexOf(_)>-1)continue;o.push(_);let v=i(m,p);for(let e=0;e<v.length;++e){let t=v[e];o.push(g+t)}c=t+(c.length>0?` `+c:c)}return c},E=(...e)=>{let t=0,n,r,i=``;for(;t<e.length;)(n=e[t++])&&(r=D(n))&&(i&&(i+=` `),i+=r);return i},D=e=>{if(typeof e==`string`)return e;let t,n=``;for(let r=0;r<e.length;r++)e[r]&&(t=D(e[r]))&&(n&&(n+=` `),n+=t);return n},O=(e,...t)=>{let n,r,i,a,o=o=>(n=ne(t.reduce((e,t)=>t(e),e())),r=n.cache.get,i=n.cache.set,a=s,s(o)),s=e=>{let t=r(e);if(t)return t;let a=re(e,n);return i(e,a),a};return a=o,(...e)=>a(E(...e))},k=[],A=e=>{let t=t=>t[e]||k;return t.isThemeGetter=!0,t},j=/^\[(?:(\w[\w-]*):)?(.+)\]$/i,M=/^\((?:(\w[\w-]*):)?(.+)\)$/i,N=/^\d+(?:\.\d+)?\/\d+(?:\.\d+)?$/,ie=/^(\d+(\.\d+)?)?(xs|sm|md|lg|xl)$/,ae=/\d+(%|px|r?em|[sdl]?v([hwib]|min|max)|pt|pc|in|cm|mm|cap|ch|ex|r?lh|cq(w|h|i|b|min|max))|\b(calc|min|max|clamp)\(.+\)|^0$/,oe=/^(rgba?|hsla?|hwb|(ok)?(lab|lch)|color-mix)\(.+\)$/,P=/^(inset_)?-?((\d+)?\.?(\d+)[a-z]+|0)_-?((\d+)?\.?(\d+)[a-z]+|0)/,F=/^(url|image|image-set|cross-fade|element|(repeating-)?(linear|radial|conic)-gradient)\(.+\)$/,I=e=>N.test(e),L=e=>!!e&&!Number.isNaN(Number(e)),R=e=>!!e&&Number.isInteger(Number(e)),se=e=>e.endsWith(`%`)&&L(e.slice(0,-1)),z=e=>ie.test(e),ce=()=>!0,B=e=>ae.test(e)&&!oe.test(e),V=()=>!1,le=e=>P.test(e),H=e=>F.test(e),ue=e=>!U(e)&&!K(e),de=e=>Y(e,$,V),U=e=>j.test(e),W=e=>Y(e,Se,B),fe=e=>Y(e,Ce,L),pe=e=>Y(e,Te,ce),me=e=>Y(e,we,V),he=e=>Y(e,Z,V),ge=e=>Y(e,Q,H),G=e=>Y(e,Ee,le),K=e=>M.test(e),q=e=>X(e,Se),_e=e=>X(e,we),ve=e=>X(e,Z),ye=e=>X(e,$),be=e=>X(e,Q),J=e=>X(e,Ee,!0),xe=e=>X(e,Te,!0),Y=(e,t,n)=>{let r=j.exec(e);return r?r[1]?t(r[1]):n(r[2]):!1},X=(e,t,n=!1)=>{let r=M.exec(e);return r?r[1]?t(r[1]):n:!1},Z=e=>e===`position`||e===`percentage`,Q=e=>e===`image`||e===`url`,$=e=>e===`length`||e===`size`||e===`bg-size`,Se=e=>e===`length`,Ce=e=>e===`number`,we=e=>e===`family-name`,Te=e=>e===`number`||e===`weight`,Ee=e=>e===`shadow`,De=O(()=>{let e=A(`color`),t=A(`font`),n=A(`text`),r=A(`font-weight`),i=A(`tracking`),a=A(`leading`),o=A(`breakpoint`),s=A(`container`),c=A(`spacing`),l=A(`radius`),u=A(`shadow`),ee=A(`inset-shadow`),d=A(`text-shadow`),f=A(`drop-shadow`),p=A(`blur`),m=A(`perspective`),h=A(`aspect`),g=A(`ease`),_=A(`animate`),v=()=>[`auto`,`avoid`,`all`,`avoid-page`,`page`,`left`,`right`,`column`],y=()=>[`center`,`top`,`bottom`,`left`,`right`,`top-left`,`left-top`,`top-right`,`right-top`,`bottom-right`,`right-bottom`,`bottom-left`,`left-bottom`],b=()=>[...y(),K,U],x=()=>[`auto`,`hidden`,`clip`,`visible`,`scroll`],S=()=>[`auto`,`contain`,`none`],C=()=>[K,U,c],w=()=>[I,`full`,`auto`,...C()],te=()=>[R,`none`,`subgrid`,K,U],ne=()=>[`auto`,{span:[`full`,R,K,U]},R,K,U],T=()=>[R,`auto`,K,U],re=()=>[`auto`,`min`,`max`,`fr`,K,U],E=()=>[`start`,`end`,`center`,`between`,`around`,`evenly`,`stretch`,`baseline`,`center-safe`,`end-safe`],D=()=>[`start`,`end`,`center`,`stretch`,`center-safe`,`end-safe`],O=()=>[`auto`,...C()],k=()=>[I,`auto`,`full`,`dvw`,`dvh`,`lvw`,`lvh`,`svw`,`svh`,`min`,`max`,`fit`,...C()],j=()=>[I,`screen`,`full`,`dvw`,`lvw`,`svw`,`min`,`max`,`fit`,...C()],M=()=>[I,`screen`,`full`,`lh`,`dvh`,`lvh`,`svh`,`min`,`max`,`fit`,...C()],N=()=>[e,K,U],ie=()=>[...y(),ve,he,{position:[K,U]}],ae=()=>[`no-repeat`,{repeat:[``,`x`,`y`,`space`,`round`]}],oe=()=>[`auto`,`cover`,`contain`,ye,de,{size:[K,U]}],P=()=>[se,q,W],F=()=>[``,`none`,`full`,l,K,U],B=()=>[``,L,q,W],V=()=>[`solid`,`dashed`,`dotted`,`double`],le=()=>[`normal`,`multiply`,`screen`,`overlay`,`darken`,`lighten`,`color-dodge`,`color-burn`,`hard-light`,`soft-light`,`difference`,`exclusion`,`hue`,`saturation`,`color`,`luminosity`],H=()=>[L,se,ve,he],Y=()=>[``,`none`,p,K,U],X=()=>[`none`,L,K,U],Z=()=>[`none`,L,K,U],Q=()=>[L,K,U],$=()=>[I,`full`,...C()];return{cacheSize:500,theme:{animate:[`spin`,`ping`,`pulse`,`bounce`],aspect:[`video`],blur:[z],breakpoint:[z],color:[ce],container:[z],"drop-shadow":[z],ease:[`in`,`out`,`in-out`],font:[ue],"font-weight":[`thin`,`extralight`,`light`,`normal`,`medium`,`semibold`,`bold`,`extrabold`,`black`],"inset-shadow":[z],leading:[`none`,`tight`,`snug`,`normal`,`relaxed`,`loose`],perspective:[`dramatic`,`near`,`normal`,`midrange`,`distant`,`none`],radius:[z],shadow:[z],spacing:[`px`,L],text:[z],"text-shadow":[z],tracking:[`tighter`,`tight`,`normal`,`wide`,`wider`,`widest`]},classGroups:{aspect:[{aspect:[`auto`,`square`,I,U,K,h]}],container:[`container`],columns:[{columns:[L,U,K,s]}],"break-after":[{"break-after":v()}],"break-before":[{"break-before":v()}],"break-inside":[{"break-inside":[`auto`,`avoid`,`avoid-page`,`avoid-column`]}],"box-decoration":[{"box-decoration":[`slice`,`clone`]}],box:[{box:[`border`,`content`]}],display:[`block`,`inline-block`,`inline`,`flex`,`inline-flex`,`table`,`inline-table`,`table-caption`,`table-cell`,`table-column`,`table-column-group`,`table-footer-group`,`table-header-group`,`table-row-group`,`table-row`,`flow-root`,`grid`,`inline-grid`,`contents`,`list-item`,`hidden`],sr:[`sr-only`,`not-sr-only`],float:[{float:[`right`,`left`,`none`,`start`,`end`]}],clear:[{clear:[`left`,`right`,`both`,`none`,`start`,`end`]}],isolation:[`isolate`,`isolation-auto`],"object-fit":[{object:[`contain`,`cover`,`fill`,`none`,`scale-down`]}],"object-position":[{object:b()}],overflow:[{overflow:x()}],"overflow-x":[{"overflow-x":x()}],"overflow-y":[{"overflow-y":x()}],overscroll:[{overscroll:S()}],"overscroll-x":[{"overscroll-x":S()}],"overscroll-y":[{"overscroll-y":S()}],position:[`static`,`fixed`,`absolute`,`relative`,`sticky`],inset:[{inset:w()}],"inset-x":[{"inset-x":w()}],"inset-y":[{"inset-y":w()}],start:[{"inset-s":w(),start:w()}],end:[{"inset-e":w(),end:w()}],"inset-bs":[{"inset-bs":w()}],"inset-be":[{"inset-be":w()}],top:[{top:w()}],right:[{right:w()}],bottom:[{bottom:w()}],left:[{left:w()}],visibility:[`visible`,`invisible`,`collapse`],z:[{z:[R,`auto`,K,U]}],basis:[{basis:[I,`full`,`auto`,s,...C()]}],"flex-direction":[{flex:[`row`,`row-reverse`,`col`,`col-reverse`]}],"flex-wrap":[{flex:[`nowrap`,`wrap`,`wrap-reverse`]}],flex:[{flex:[L,I,`auto`,`initial`,`none`,U]}],grow:[{grow:[``,L,K,U]}],shrink:[{shrink:[``,L,K,U]}],order:[{order:[R,`first`,`last`,`none`,K,U]}],"grid-cols":[{"grid-cols":te()}],"col-start-end":[{col:ne()}],"col-start":[{"col-start":T()}],"col-end":[{"col-end":T()}],"grid-rows":[{"grid-rows":te()}],"row-start-end":[{row:ne()}],"row-start":[{"row-start":T()}],"row-end":[{"row-end":T()}],"grid-flow":[{"grid-flow":[`row`,`col`,`dense`,`row-dense`,`col-dense`]}],"auto-cols":[{"auto-cols":re()}],"auto-rows":[{"auto-rows":re()}],gap:[{gap:C()}],"gap-x":[{"gap-x":C()}],"gap-y":[{"gap-y":C()}],"justify-content":[{justify:[...E(),`normal`]}],"justify-items":[{"justify-items":[...D(),`normal`]}],"justify-self":[{"justify-self":[`auto`,...D()]}],"align-content":[{content:[`normal`,...E()]}],"align-items":[{items:[...D(),{baseline:[``,`last`]}]}],"align-self":[{self:[`auto`,...D(),{baseline:[``,`last`]}]}],"place-content":[{"place-content":E()}],"place-items":[{"place-items":[...D(),`baseline`]}],"place-self":[{"place-self":[`auto`,...D()]}],p:[{p:C()}],px:[{px:C()}],py:[{py:C()}],ps:[{ps:C()}],pe:[{pe:C()}],pbs:[{pbs:C()}],pbe:[{pbe:C()}],pt:[{pt:C()}],pr:[{pr:C()}],pb:[{pb:C()}],pl:[{pl:C()}],m:[{m:O()}],mx:[{mx:O()}],my:[{my:O()}],ms:[{ms:O()}],me:[{me:O()}],mbs:[{mbs:O()}],mbe:[{mbe:O()}],mt:[{mt:O()}],mr:[{mr:O()}],mb:[{mb:O()}],ml:[{ml:O()}],"space-x":[{"space-x":C()}],"space-x-reverse":[`space-x-reverse`],"space-y":[{"space-y":C()}],"space-y-reverse":[`space-y-reverse`],size:[{size:k()}],"inline-size":[{inline:[`auto`,...j()]}],"min-inline-size":[{"min-inline":[`auto`,...j()]}],"max-inline-size":[{"max-inline":[`none`,...j()]}],"block-size":[{block:[`auto`,...M()]}],"min-block-size":[{"min-block":[`auto`,...M()]}],"max-block-size":[{"max-block":[`none`,...M()]}],w:[{w:[s,`screen`,...k()]}],"min-w":[{"min-w":[s,`screen`,`none`,...k()]}],"max-w":[{"max-w":[s,`screen`,`none`,`prose`,{screen:[o]},...k()]}],h:[{h:[`screen`,`lh`,...k()]}],"min-h":[{"min-h":[`screen`,`lh`,`none`,...k()]}],"max-h":[{"max-h":[`screen`,`lh`,...k()]}],"font-size":[{text:[`base`,n,q,W]}],"font-smoothing":[`antialiased`,`subpixel-antialiased`],"font-style":[`italic`,`not-italic`],"font-weight":[{font:[r,xe,pe]}],"font-stretch":[{"font-stretch":[`ultra-condensed`,`extra-condensed`,`condensed`,`semi-condensed`,`normal`,`semi-expanded`,`expanded`,`extra-expanded`,`ultra-expanded`,se,U]}],"font-family":[{font:[_e,me,t]}],"font-features":[{"font-features":[U]}],"fvn-normal":[`normal-nums`],"fvn-ordinal":[`ordinal`],"fvn-slashed-zero":[`slashed-zero`],"fvn-figure":[`lining-nums`,`oldstyle-nums`],"fvn-spacing":[`proportional-nums`,`tabular-nums`],"fvn-fraction":[`diagonal-fractions`,`stacked-fractions`],tracking:[{tracking:[i,K,U]}],"line-clamp":[{"line-clamp":[L,`none`,K,fe]}],leading:[{leading:[a,...C()]}],"list-image":[{"list-image":[`none`,K,U]}],"list-style-position":[{list:[`inside`,`outside`]}],"list-style-type":[{list:[`disc`,`decimal`,`none`,K,U]}],"text-alignment":[{text:[`left`,`center`,`right`,`justify`,`start`,`end`]}],"placeholder-color":[{placeholder:N()}],"text-color":[{text:N()}],"text-decoration":[`underline`,`overline`,`line-through`,`no-underline`],"text-decoration-style":[{decoration:[...V(),`wavy`]}],"text-decoration-thickness":[{decoration:[L,`from-font`,`auto`,K,W]}],"text-decoration-color":[{decoration:N()}],"underline-offset":[{"underline-offset":[L,`auto`,K,U]}],"text-transform":[`uppercase`,`lowercase`,`capitalize`,`normal-case`],"text-overflow":[`truncate`,`text-ellipsis`,`text-clip`],"text-wrap":[{text:[`wrap`,`nowrap`,`balance`,`pretty`]}],indent:[{indent:C()}],"vertical-align":[{align:[`baseline`,`top`,`middle`,`bottom`,`text-top`,`text-bottom`,`sub`,`super`,K,U]}],whitespace:[{whitespace:[`normal`,`nowrap`,`pre`,`pre-line`,`pre-wrap`,`break-spaces`]}],break:[{break:[`normal`,`words`,`all`,`keep`]}],wrap:[{wrap:[`break-word`,`anywhere`,`normal`]}],hyphens:[{hyphens:[`none`,`manual`,`auto`]}],content:[{content:[`none`,K,U]}],"bg-attachment":[{bg:[`fixed`,`local`,`scroll`]}],"bg-clip":[{"bg-clip":[`border`,`padding`,`content`,`text`]}],"bg-origin":[{"bg-origin":[`border`,`padding`,`content`]}],"bg-position":[{bg:ie()}],"bg-repeat":[{bg:ae()}],"bg-size":[{bg:oe()}],"bg-image":[{bg:[`none`,{linear:[{to:[`t`,`tr`,`r`,`br`,`b`,`bl`,`l`,`tl`]},R,K,U],radial:[``,K,U],conic:[R,K,U]},be,ge]}],"bg-color":[{bg:N()}],"gradient-from-pos":[{from:P()}],"gradient-via-pos":[{via:P()}],"gradient-to-pos":[{to:P()}],"gradient-from":[{from:N()}],"gradient-via":[{via:N()}],"gradient-to":[{to:N()}],rounded:[{rounded:F()}],"rounded-s":[{"rounded-s":F()}],"rounded-e":[{"rounded-e":F()}],"rounded-t":[{"rounded-t":F()}],"rounded-r":[{"rounded-r":F()}],"rounded-b":[{"rounded-b":F()}],"rounded-l":[{"rounded-l":F()}],"rounded-ss":[{"rounded-ss":F()}],"rounded-se":[{"rounded-se":F()}],"rounded-ee":[{"rounded-ee":F()}],"rounded-es":[{"rounded-es":F()}],"rounded-tl":[{"rounded-tl":F()}],"rounded-tr":[{"rounded-tr":F()}],"rounded-br":[{"rounded-br":F()}],"rounded-bl":[{"rounded-bl":F()}],"border-w":[{border:B()}],"border-w-x":[{"border-x":B()}],"border-w-y":[{"border-y":B()}],"border-w-s":[{"border-s":B()}],"border-w-e":[{"border-e":B()}],"border-w-bs":[{"border-bs":B()}],"border-w-be":[{"border-be":B()}],"border-w-t":[{"border-t":B()}],"border-w-r":[{"border-r":B()}],"border-w-b":[{"border-b":B()}],"border-w-l":[{"border-l":B()}],"divide-x":[{"divide-x":B()}],"divide-x-reverse":[`divide-x-reverse`],"divide-y":[{"divide-y":B()}],"divide-y-reverse":[`divide-y-reverse`],"border-style":[{border:[...V(),`hidden`,`none`]}],"divide-style":[{divide:[...V(),`hidden`,`none`]}],"border-color":[{border:N()}],"border-color-x":[{"border-x":N()}],"border-color-y":[{"border-y":N()}],"border-color-s":[{"border-s":N()}],"border-color-e":[{"border-e":N()}],"border-color-bs":[{"border-bs":N()}],"border-color-be":[{"border-be":N()}],"border-color-t":[{"border-t":N()}],"border-color-r":[{"border-r":N()}],"border-color-b":[{"border-b":N()}],"border-color-l":[{"border-l":N()}],"divide-color":[{divide:N()}],"outline-style":[{outline:[...V(),`none`,`hidden`]}],"outline-offset":[{"outline-offset":[L,K,U]}],"outline-w":[{outline:[``,L,q,W]}],"outline-color":[{outline:N()}],shadow:[{shadow:[``,`none`,u,J,G]}],"shadow-color":[{shadow:N()}],"inset-shadow":[{"inset-shadow":[`none`,ee,J,G]}],"inset-shadow-color":[{"inset-shadow":N()}],"ring-w":[{ring:B()}],"ring-w-inset":[`ring-inset`],"ring-color":[{ring:N()}],"ring-offset-w":[{"ring-offset":[L,W]}],"ring-offset-color":[{"ring-offset":N()}],"inset-ring-w":[{"inset-ring":B()}],"inset-ring-color":[{"inset-ring":N()}],"text-shadow":[{"text-shadow":[`none`,d,J,G]}],"text-shadow-color":[{"text-shadow":N()}],opacity:[{opacity:[L,K,U]}],"mix-blend":[{"mix-blend":[...le(),`plus-darker`,`plus-lighter`]}],"bg-blend":[{"bg-blend":le()}],"mask-clip":[{"mask-clip":[`border`,`padding`,`content`,`fill`,`stroke`,`view`]},`mask-no-clip`],"mask-composite":[{mask:[`add`,`subtract`,`intersect`,`exclude`]}],"mask-image-linear-pos":[{"mask-linear":[L]}],"mask-image-linear-from-pos":[{"mask-linear-from":H()}],"mask-image-linear-to-pos":[{"mask-linear-to":H()}],"mask-image-linear-from-color":[{"mask-linear-from":N()}],"mask-image-linear-to-color":[{"mask-linear-to":N()}],"mask-image-t-from-pos":[{"mask-t-from":H()}],"mask-image-t-to-pos":[{"mask-t-to":H()}],"mask-image-t-from-color":[{"mask-t-from":N()}],"mask-image-t-to-color":[{"mask-t-to":N()}],"mask-image-r-from-pos":[{"mask-r-from":H()}],"mask-image-r-to-pos":[{"mask-r-to":H()}],"mask-image-r-from-color":[{"mask-r-from":N()}],"mask-image-r-to-color":[{"mask-r-to":N()}],"mask-image-b-from-pos":[{"mask-b-from":H()}],"mask-image-b-to-pos":[{"mask-b-to":H()}],"mask-image-b-from-color":[{"mask-b-from":N()}],"mask-image-b-to-color":[{"mask-b-to":N()}],"mask-image-l-from-pos":[{"mask-l-from":H()}],"mask-image-l-to-pos":[{"mask-l-to":H()}],"mask-image-l-from-color":[{"mask-l-from":N()}],"mask-image-l-to-color":[{"mask-l-to":N()}],"mask-image-x-from-pos":[{"mask-x-from":H()}],"mask-image-x-to-pos":[{"mask-x-to":H()}],"mask-image-x-from-color":[{"mask-x-from":N()}],"mask-image-x-to-color":[{"mask-x-to":N()}],"mask-image-y-from-pos":[{"mask-y-from":H()}],"mask-image-y-to-pos":[{"mask-y-to":H()}],"mask-image-y-from-color":[{"mask-y-from":N()}],"mask-image-y-to-color":[{"mask-y-to":N()}],"mask-image-radial":[{"mask-radial":[K,U]}],"mask-image-radial-from-pos":[{"mask-radial-from":H()}],"mask-image-radial-to-pos":[{"mask-radial-to":H()}],"mask-image-radial-from-color":[{"mask-radial-from":N()}],"mask-image-radial-to-color":[{"mask-radial-to":N()}],"mask-image-radial-shape":[{"mask-radial":[`circle`,`ellipse`]}],"mask-image-radial-size":[{"mask-radial":[{closest:[`side`,`corner`],farthest:[`side`,`corner`]}]}],"mask-image-radial-pos":[{"mask-radial-at":y()}],"mask-image-conic-pos":[{"mask-conic":[L]}],"mask-image-conic-from-pos":[{"mask-conic-from":H()}],"mask-image-conic-to-pos":[{"mask-conic-to":H()}],"mask-image-conic-from-color":[{"mask-conic-from":N()}],"mask-image-conic-to-color":[{"mask-conic-to":N()}],"mask-mode":[{mask:[`alpha`,`luminance`,`match`]}],"mask-origin":[{"mask-origin":[`border`,`padding`,`content`,`fill`,`stroke`,`view`]}],"mask-position":[{mask:ie()}],"mask-repeat":[{mask:ae()}],"mask-size":[{mask:oe()}],"mask-type":[{"mask-type":[`alpha`,`luminance`]}],"mask-image":[{mask:[`none`,K,U]}],filter:[{filter:[``,`none`,K,U]}],blur:[{blur:Y()}],brightness:[{brightness:[L,K,U]}],contrast:[{contrast:[L,K,U]}],"drop-shadow":[{"drop-shadow":[``,`none`,f,J,G]}],"drop-shadow-color":[{"drop-shadow":N()}],grayscale:[{grayscale:[``,L,K,U]}],"hue-rotate":[{"hue-rotate":[L,K,U]}],invert:[{invert:[``,L,K,U]}],saturate:[{saturate:[L,K,U]}],sepia:[{sepia:[``,L,K,U]}],"backdrop-filter":[{"backdrop-filter":[``,`none`,K,U]}],"backdrop-blur":[{"backdrop-blur":Y()}],"backdrop-brightness":[{"backdrop-brightness":[L,K,U]}],"backdrop-contrast":[{"backdrop-contrast":[L,K,U]}],"backdrop-grayscale":[{"backdrop-grayscale":[``,L,K,U]}],"backdrop-hue-rotate":[{"backdrop-hue-rotate":[L,K,U]}],"backdrop-invert":[{"backdrop-invert":[``,L,K,U]}],"backdrop-opacity":[{"backdrop-opacity":[L,K,U]}],"backdrop-saturate":[{"backdrop-saturate":[L,K,U]}],"backdrop-sepia":[{"backdrop-sepia":[``,L,K,U]}],"border-collapse":[{border:[`collapse`,`separate`]}],"border-spacing":[{"border-spacing":C()}],"border-spacing-x":[{"border-spacing-x":C()}],"border-spacing-y":[{"border-spacing-y":C()}],"table-layout":[{table:[`auto`,`fixed`]}],caption:[{caption:[`top`,`bottom`]}],transition:[{transition:[``,`all`,`colors`,`opacity`,`shadow`,`transform`,`none`,K,U]}],"transition-behavior":[{transition:[`normal`,`discrete`]}],duration:[{duration:[L,`initial`,K,U]}],ease:[{ease:[`linear`,`initial`,g,K,U]}],delay:[{delay:[L,K,U]}],animate:[{animate:[`none`,_,K,U]}],backface:[{backface:[`hidden`,`visible`]}],perspective:[{perspective:[m,K,U]}],"perspective-origin":[{"perspective-origin":b()}],rotate:[{rotate:X()}],"rotate-x":[{"rotate-x":X()}],"rotate-y":[{"rotate-y":X()}],"rotate-z":[{"rotate-z":X()}],scale:[{scale:Z()}],"scale-x":[{"scale-x":Z()}],"scale-y":[{"scale-y":Z()}],"scale-z":[{"scale-z":Z()}],"scale-3d":[`scale-3d`],skew:[{skew:Q()}],"skew-x":[{"skew-x":Q()}],"skew-y":[{"skew-y":Q()}],transform:[{transform:[K,U,``,`none`,`gpu`,`cpu`]}],"transform-origin":[{origin:b()}],"transform-style":[{transform:[`3d`,`flat`]}],translate:[{translate:$()}],"translate-x":[{"translate-x":$()}],"translate-y":[{"translate-y":$()}],"translate-z":[{"translate-z":$()}],"translate-none":[`translate-none`],accent:[{accent:N()}],appearance:[{appearance:[`none`,`auto`]}],"caret-color":[{caret:N()}],"color-scheme":[{scheme:[`normal`,`dark`,`light`,`light-dark`,`only-dark`,`only-light`]}],cursor:[{cursor:[`auto`,`default`,`pointer`,`wait`,`text`,`move`,`help`,`not-allowed`,`none`,`context-menu`,`progress`,`cell`,`crosshair`,`vertical-text`,`alias`,`copy`,`no-drop`,`grab`,`grabbing`,`all-scroll`,`col-resize`,`row-resize`,`n-resize`,`e-resize`,`s-resize`,`w-resize`,`ne-resize`,`nw-resize`,`se-resize`,`sw-resize`,`ew-resize`,`ns-resize`,`nesw-resize`,`nwse-resize`,`zoom-in`,`zoom-out`,K,U]}],"field-sizing":[{"field-sizing":[`fixed`,`content`]}],"pointer-events":[{"pointer-events":[`auto`,`none`]}],resize:[{resize:[`none`,``,`y`,`x`]}],"scroll-behavior":[{scroll:[`auto`,`smooth`]}],"scroll-m":[{"scroll-m":C()}],"scroll-mx":[{"scroll-mx":C()}],"scroll-my":[{"scroll-my":C()}],"scroll-ms":[{"scroll-ms":C()}],"scroll-me":[{"scroll-me":C()}],"scroll-mbs":[{"scroll-mbs":C()}],"scroll-mbe":[{"scroll-mbe":C()}],"scroll-mt":[{"scroll-mt":C()}],"scroll-mr":[{"scroll-mr":C()}],"scroll-mb":[{"scroll-mb":C()}],"scroll-ml":[{"scroll-ml":C()}],"scroll-p":[{"scroll-p":C()}],"scroll-px":[{"scroll-px":C()}],"scroll-py":[{"scroll-py":C()}],"scroll-ps":[{"scroll-ps":C()}],"scroll-pe":[{"scroll-pe":C()}],"scroll-pbs":[{"scroll-pbs":C()}],"scroll-pbe":[{"scroll-pbe":C()}],"scroll-pt":[{"scroll-pt":C()}],"scroll-pr":[{"scroll-pr":C()}],"scroll-pb":[{"scroll-pb":C()}],"scroll-pl":[{"scroll-pl":C()}],"snap-align":[{snap:[`start`,`end`,`center`,`align-none`]}],"snap-stop":[{snap:[`normal`,`always`]}],"snap-type":[{snap:[`none`,`x`,`y`,`both`]}],"snap-strictness":[{snap:[`mandatory`,`proximity`]}],touch:[{touch:[`auto`,`none`,`manipulation`]}],"touch-x":[{"touch-pan":[`x`,`left`,`right`]}],"touch-y":[{"touch-pan":[`y`,`up`,`down`]}],"touch-pz":[`touch-pinch-zoom`],select:[{select:[`none`,`text`,`all`,`auto`]}],"will-change":[{"will-change":[`auto`,`scroll`,`contents`,`transform`,K,U]}],fill:[{fill:[`none`,...N()]}],"stroke-w":[{stroke:[L,q,W,fe]}],stroke:[{stroke:[`none`,...N()]}],"forced-color-adjust":[{"forced-color-adjust":[`auto`,`none`]}]},conflictingClassGroups:{overflow:[`overflow-x`,`overflow-y`],overscroll:[`overscroll-x`,`overscroll-y`],inset:[`inset-x`,`inset-y`,`inset-bs`,`inset-be`,`start`,`end`,`top`,`right`,`bottom`,`left`],"inset-x":[`right`,`left`],"inset-y":[`top`,`bottom`],flex:[`basis`,`grow`,`shrink`],gap:[`gap-x`,`gap-y`],p:[`px`,`py`,`ps`,`pe`,`pbs`,`pbe`,`pt`,`pr`,`pb`,`pl`],px:[`pr`,`pl`],py:[`pt`,`pb`],m:[`mx`,`my`,`ms`,`me`,`mbs`,`mbe`,`mt`,`mr`,`mb`,`ml`],mx:[`mr`,`ml`],my:[`mt`,`mb`],size:[`w`,`h`],"font-size":[`leading`],"fvn-normal":[`fvn-ordinal`,`fvn-slashed-zero`,`fvn-figure`,`fvn-spacing`,`fvn-fraction`],"fvn-ordinal":[`fvn-normal`],"fvn-slashed-zero":[`fvn-normal`],"fvn-figure":[`fvn-normal`],"fvn-spacing":[`fvn-normal`],"fvn-fraction":[`fvn-normal`],"line-clamp":[`display`,`overflow`],rounded:[`rounded-s`,`rounded-e`,`rounded-t`,`rounded-r`,`rounded-b`,`rounded-l`,`rounded-ss`,`rounded-se`,`rounded-ee`,`rounded-es`,`rounded-tl`,`rounded-tr`,`rounded-br`,`rounded-bl`],"rounded-s":[`rounded-ss`,`rounded-es`],"rounded-e":[`rounded-se`,`rounded-ee`],"rounded-t":[`rounded-tl`,`rounded-tr`],"rounded-r":[`rounded-tr`,`rounded-br`],"rounded-b":[`rounded-br`,`rounded-bl`],"rounded-l":[`rounded-tl`,`rounded-bl`],"border-spacing":[`border-spacing-x`,`border-spacing-y`],"border-w":[`border-w-x`,`border-w-y`,`border-w-s`,`border-w-e`,`border-w-bs`,`border-w-be`,`border-w-t`,`border-w-r`,`border-w-b`,`border-w-l`],"border-w-x":[`border-w-r`,`border-w-l`],"border-w-y":[`border-w-t`,`border-w-b`],"border-color":[`border-color-x`,`border-color-y`,`border-color-s`,`border-color-e`,`border-color-bs`,`border-color-be`,`border-color-t`,`border-color-r`,`border-color-b`,`border-color-l`],"border-color-x":[`border-color-r`,`border-color-l`],"border-color-y":[`border-color-t`,`border-color-b`],translate:[`translate-x`,`translate-y`,`translate-none`],"translate-none":[`translate`,`translate-x`,`translate-y`,`translate-z`],"scroll-m":[`scroll-mx`,`scroll-my`,`scroll-ms`,`scroll-me`,`scroll-mbs`,`scroll-mbe`,`scroll-mt`,`scroll-mr`,`scroll-mb`,`scroll-ml`],"scroll-mx":[`scroll-mr`,`scroll-ml`],"scroll-my":[`scroll-mt`,`scroll-mb`],"scroll-p":[`scroll-px`,`scroll-py`,`scroll-ps`,`scroll-pe`,`scroll-pbs`,`scroll-pbe`,`scroll-pt`,`scroll-pr`,`scroll-pb`,`scroll-pl`],"scroll-px":[`scroll-pr`,`scroll-pl`],"scroll-py":[`scroll-pt`,`scroll-pb`],touch:[`touch-x`,`touch-y`,`touch-pz`],"touch-x":[`touch`],"touch-y":[`touch`],"touch-pz":[`touch`]},conflictingClassGroupModifiers:{"font-size":[`leading`]},orderSensitiveModifiers:[`*`,`**`,`after`,`backdrop`,`before`,`details-content`,`file`,`first-letter`,`first-line`,`marker`,`placeholder`,`selection`]}});function Oe(...e){return De(t(e))}export{t as n,Oe as t};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{t as e}from"./createLucideIcon-Dy1wlrF7.js";var t=e(`x`,[[`path`,{d:`M18 6 6 18`,key:`1bl5f8`}],[`path`,{d:`m6 6 12 12`,key:`d8bk6v`}]]);export{t};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="192" height="192" viewBox="0 0 192 192">
|
|
2
|
+
<rect width="192" height="192" rx="24" fill="#0f1419"/>
|
|
3
|
+
<rect x="8" y="8" width="176" height="176" rx="20" fill="#1a1f2e"/>
|
|
4
|
+
<text x="96" y="110" text-anchor="middle" font-family="sans-serif" font-weight="700" font-size="56" fill="#3b82f6">PPM</text>
|
|
5
|
+
</svg>
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" width="192" height="192" viewBox="0 0 192 192">
|
|
2
|
+
<rect width="192" height="192" rx="24" fill="#0f1419"/>
|
|
3
|
+
<rect x="8" y="8" width="176" height="176" rx="20" fill="#1a1f2e"/>
|
|
4
|
+
<text x="96" y="110" text-anchor="middle" font-family="sans-serif" font-weight="700" font-size="56" fill="#3b82f6">PPM</text>
|
|
5
|
+
</svg>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en" class="dark">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover" />
|
|
6
|
+
<meta name="theme-color" content="#0f1419" />
|
|
7
|
+
<title>PPM — Personal Project Manager</title>
|
|
8
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
9
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
10
|
+
<link href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@400;500;600;700&family=Geist:wght@400;500;600;700&display=swap" rel="stylesheet" />
|
|
11
|
+
<script type="module" crossorigin src="/assets/index-DGSLw2GE.js"></script>
|
|
12
|
+
<link rel="modulepreload" crossorigin href="/assets/jsx-runtime-BnxRlLMJ.js">
|
|
13
|
+
<link rel="modulepreload" crossorigin href="/assets/utils-Cgi2TYRi.js">
|
|
14
|
+
<link rel="modulepreload" crossorigin href="/assets/button-BxijdhtM.js">
|
|
15
|
+
<link rel="modulepreload" crossorigin href="/assets/createLucideIcon-Dy1wlrF7.js">
|
|
16
|
+
<link rel="modulepreload" crossorigin href="/assets/x-BISR7bpK.js">
|
|
17
|
+
<link rel="modulepreload" crossorigin href="/assets/dialog-RczsXsmw.js">
|
|
18
|
+
<link rel="modulepreload" crossorigin href="/assets/api-client-Bnf9LAt4.js">
|
|
19
|
+
<link rel="modulepreload" crossorigin href="/assets/react-Uzd0zARU.js">
|
|
20
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DYd_2slk.css">
|
|
21
|
+
<link rel="manifest" href="/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/registerSW.js"></script></head>
|
|
22
|
+
<body class="bg-[#0f1419] text-[#e5e7eb] font-sans antialiased">
|
|
23
|
+
<div id="root"></div>
|
|
24
|
+
</body>
|
|
25
|
+
</html>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"name":"PPM — Personal Project Manager","short_name":"PPM","description":"Mobile-first web IDE for managing code projects","start_url":"/","display":"standalone","background_color":"#0f1419","theme_color":"#0f1419","lang":"en","scope":"/","orientation":"any","icons":[{"src":"/icon-192.png","sizes":"192x192","type":"image/png"},{"src":"/icon-512.png","sizes":"512x512","type":"image/png"}]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
if('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('/sw.js', { scope: '/' })})}
|
package/dist/web/sw.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
if(!self.define){let s,e={};const i=(i,l)=>(i=new URL(i+".js",l).href,e[i]||new Promise(e=>{if("document"in self){const s=document.createElement("script");s.src=i,s.onload=e,document.head.appendChild(s)}else s=i,importScripts(i),e()}).then(()=>{let s=e[i];if(!s)throw new Error(`Module ${i} didn’t register its module`);return s}));self.define=(l,r)=>{const n=s||("document"in self?document.currentScript.src:"")||location.href;if(e[n])return;let t={};const u=s=>i(s,n),o={module:{uri:n},exports:t,require:u};e[n]=Promise.all(l.map(s=>o[s]||u(s))).then(s=>(r(...s),t))}}define(["./workbox-3e722498"],function(s){"use strict";self.skipWaiting(),s.clientsClaim(),s.precacheAndRoute([{url:"registerSW.js",revision:"1872c500de691dce40960bb85481de07"},{url:"index.html",revision:"5bbe3db98c1f5e52e3f88df7bf70cfa0"},{url:"icon-512.svg",revision:"a0fb34fc84eb148d51812cd62669f20d"},{url:"icon-192.svg",revision:"a0fb34fc84eb148d51812cd62669f20d"},{url:"assets/x-BISR7bpK.js",revision:null},{url:"assets/utils-Cgi2TYRi.js",revision:null},{url:"assets/trash-2-CHLebaNh.js",revision:null},{url:"assets/terminal-tab-CbwaI-oq.js",revision:null},{url:"assets/terminal-tab-BrP-ENHg.css",revision:null},{url:"assets/settings-tab-DJRzIAuP.js",revision:null},{url:"assets/refresh-cw-DtopuYJf.js",revision:null},{url:"assets/react-Uzd0zARU.js",revision:null},{url:"assets/project-list-DWVXEimw.js",revision:null},{url:"assets/jsx-runtime-BnxRlLMJ.js",revision:null},{url:"assets/index-DYd_2slk.css",revision:null},{url:"assets/index-DGSLw2GE.js",revision:null},{url:"assets/git-status-panel-D8ZUQrRF.js",revision:null},{url:"assets/git-graph-DXMB_DoT.js",revision:null},{url:"assets/external-link-WSiY-639.js",revision:null},{url:"assets/dist-CSp7ir0r.js",revision:null},{url:"assets/diff-viewer-D6ixPlNB.js",revision:null},{url:"assets/dialog-RczsXsmw.js",revision:null},{url:"assets/createLucideIcon-Dy1wlrF7.js",revision:null},{url:"assets/code-editor-hbllHzj7.js",revision:null},{url:"assets/chat-tab-BZopEuub.js",revision:null},{url:"assets/button-BxijdhtM.js",revision:null},{url:"assets/arrow-up-from-line-BXL5dtbG.js",revision:null},{url:"assets/api-client-Bnf9LAt4.js",revision:null},{url:"manifest.webmanifest",revision:"79c8870653c8f419f2e3323085e1f4be"}],{}),s.cleanupOutdatedCaches(),s.registerRoute(new s.NavigationRoute(s.createHandlerBoundToURL("index.html"))),s.registerRoute(/^https?:\/\/.*\/api\//,new s.NetworkOnly,"GET"),s.registerRoute(/^https?:\/\/.*\/ws\//,new s.NetworkOnly,"GET")});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
define(["exports"],function(t){"use strict";try{self["workbox:core:7.3.0"]&&_()}catch(t){}const e=(t,...e)=>{let s=t;return e.length>0&&(s+=` :: ${JSON.stringify(e)}`),s};class s extends Error{constructor(t,s){super(e(t,s)),this.name=t,this.details=s}}try{self["workbox:routing:7.3.0"]&&_()}catch(t){}const n=t=>t&&"object"==typeof t?t:{handle:t};class r{constructor(t,e,s="GET"){this.handler=n(e),this.match=t,this.method=s}setCatchHandler(t){this.catchHandler=n(t)}}class i extends r{constructor(t,e,s){super(({url:e})=>{const s=t.exec(e.href);if(s&&(e.origin===location.origin||0===s.index))return s.slice(1)},e,s)}}class o{constructor(){this.t=new Map,this.i=new Map}get routes(){return this.t}addFetchListener(){self.addEventListener("fetch",t=>{const{request:e}=t,s=this.handleRequest({request:e,event:t});s&&t.respondWith(s)})}addCacheListener(){self.addEventListener("message",t=>{if(t.data&&"CACHE_URLS"===t.data.type){const{payload:e}=t.data,s=Promise.all(e.urlsToCache.map(e=>{"string"==typeof e&&(e=[e]);const s=new Request(...e);return this.handleRequest({request:s,event:t})}));t.waitUntil(s),t.ports&&t.ports[0]&&s.then(()=>t.ports[0].postMessage(!0))}})}handleRequest({request:t,event:e}){const s=new URL(t.url,location.href);if(!s.protocol.startsWith("http"))return;const n=s.origin===location.origin,{params:r,route:i}=this.findMatchingRoute({event:e,request:t,sameOrigin:n,url:s});let o=i&&i.handler;const c=t.method;if(!o&&this.i.has(c)&&(o=this.i.get(c)),!o)return;let a;try{a=o.handle({url:s,request:t,event:e,params:r})}catch(t){a=Promise.reject(t)}const h=i&&i.catchHandler;return a instanceof Promise&&(this.o||h)&&(a=a.catch(async n=>{if(h)try{return await h.handle({url:s,request:t,event:e,params:r})}catch(t){t instanceof Error&&(n=t)}if(this.o)return this.o.handle({url:s,request:t,event:e});throw n})),a}findMatchingRoute({url:t,sameOrigin:e,request:s,event:n}){const r=this.t.get(s.method)||[];for(const i of r){let r;const o=i.match({url:t,sameOrigin:e,request:s,event:n});if(o)return r=o,(Array.isArray(r)&&0===r.length||o.constructor===Object&&0===Object.keys(o).length||"boolean"==typeof o)&&(r=void 0),{route:i,params:r}}return{}}setDefaultHandler(t,e="GET"){this.i.set(e,n(t))}setCatchHandler(t){this.o=n(t)}registerRoute(t){this.t.has(t.method)||this.t.set(t.method,[]),this.t.get(t.method).push(t)}unregisterRoute(t){if(!this.t.has(t.method))throw new s("unregister-route-but-not-found-with-method",{method:t.method});const e=this.t.get(t.method).indexOf(t);if(!(e>-1))throw new s("unregister-route-route-not-registered");this.t.get(t.method).splice(e,1)}}let c;const a=()=>(c||(c=new o,c.addFetchListener(),c.addCacheListener()),c);function h(t,e,n){let o;if("string"==typeof t){const s=new URL(t,location.href);o=new r(({url:t})=>t.href===s.href,e,n)}else if(t instanceof RegExp)o=new i(t,e,n);else if("function"==typeof t)o=new r(t,e,n);else{if(!(t instanceof r))throw new s("unsupported-route-type",{moduleName:"workbox-routing",funcName:"registerRoute",paramName:"capture"});o=t}return a().registerRoute(o),o}function u(t){return new Promise(e=>setTimeout(e,t))}const l={googleAnalytics:"googleAnalytics",precache:"precache-v2",prefix:"workbox",runtime:"runtime",suffix:"undefined"!=typeof registration?registration.scope:""},f=t=>[l.prefix,t,l.suffix].filter(t=>t&&t.length>0).join("-"),w=t=>t||f(l.precache),d=t=>t||f(l.runtime);function p(t,e){const s=new URL(t);for(const t of e)s.searchParams.delete(t);return s.href}class y{constructor(){this.promise=new Promise((t,e)=>{this.resolve=t,this.reject=e})}}const g=new Set;try{self["workbox:strategies:7.3.0"]&&_()}catch(t){}function R(t){return"string"==typeof t?new Request(t):t}class m{constructor(t,e){this.h={},Object.assign(this,e),this.event=e.event,this.u=t,this.l=new y,this.p=[],this.R=[...t.plugins],this.m=new Map;for(const t of this.R)this.m.set(t,{});this.event.waitUntil(this.l.promise)}async fetch(t){const{event:e}=this;let n=R(t);if("navigate"===n.mode&&e instanceof FetchEvent&&e.preloadResponse){const t=await e.preloadResponse;if(t)return t}const r=this.hasCallback("fetchDidFail")?n.clone():null;try{for(const t of this.iterateCallbacks("requestWillFetch"))n=await t({request:n.clone(),event:e})}catch(t){if(t instanceof Error)throw new s("plugin-error-request-will-fetch",{thrownErrorMessage:t.message})}const i=n.clone();try{let t;t=await fetch(n,"navigate"===n.mode?void 0:this.u.fetchOptions);for(const s of this.iterateCallbacks("fetchDidSucceed"))t=await s({event:e,request:i,response:t});return t}catch(t){throw r&&await this.runCallbacks("fetchDidFail",{error:t,event:e,originalRequest:r.clone(),request:i.clone()}),t}}async fetchAndCachePut(t){const e=await this.fetch(t),s=e.clone();return this.waitUntil(this.cachePut(t,s)),e}async cacheMatch(t){const e=R(t);let s;const{cacheName:n,matchOptions:r}=this.u,i=await this.getCacheKey(e,"read"),o=Object.assign(Object.assign({},r),{cacheName:n});s=await caches.match(i,o);for(const t of this.iterateCallbacks("cachedResponseWillBeUsed"))s=await t({cacheName:n,matchOptions:r,cachedResponse:s,request:i,event:this.event})||void 0;return s}async cachePut(t,e){const n=R(t);await u(0);const r=await this.getCacheKey(n,"write");if(!e)throw new s("cache-put-with-no-response",{url:(i=r.url,new URL(String(i),location.href).href.replace(new RegExp(`^${location.origin}`),""))});var i;const o=await this.v(e);if(!o)return!1;const{cacheName:c,matchOptions:a}=this.u,h=await self.caches.open(c),l=this.hasCallback("cacheDidUpdate"),f=l?await async function(t,e,s,n){const r=p(e.url,s);if(e.url===r)return t.match(e,n);const i=Object.assign(Object.assign({},n),{ignoreSearch:!0}),o=await t.keys(e,i);for(const e of o)if(r===p(e.url,s))return t.match(e,n)}(h,r.clone(),["__WB_REVISION__"],a):null;try{await h.put(r,l?o.clone():o)}catch(t){if(t instanceof Error)throw"QuotaExceededError"===t.name&&await async function(){for(const t of g)await t()}(),t}for(const t of this.iterateCallbacks("cacheDidUpdate"))await t({cacheName:c,oldResponse:f,newResponse:o.clone(),request:r,event:this.event});return!0}async getCacheKey(t,e){const s=`${t.url} | ${e}`;if(!this.h[s]){let n=t;for(const t of this.iterateCallbacks("cacheKeyWillBeUsed"))n=R(await t({mode:e,request:n,event:this.event,params:this.params}));this.h[s]=n}return this.h[s]}hasCallback(t){for(const e of this.u.plugins)if(t in e)return!0;return!1}async runCallbacks(t,e){for(const s of this.iterateCallbacks(t))await s(e)}*iterateCallbacks(t){for(const e of this.u.plugins)if("function"==typeof e[t]){const s=this.m.get(e),n=n=>{const r=Object.assign(Object.assign({},n),{state:s});return e[t](r)};yield n}}waitUntil(t){return this.p.push(t),t}async doneWaiting(){for(;this.p.length;){const t=this.p.splice(0),e=(await Promise.allSettled(t)).find(t=>"rejected"===t.status);if(e)throw e.reason}}destroy(){this.l.resolve(null)}async v(t){let e=t,s=!1;for(const t of this.iterateCallbacks("cacheWillUpdate"))if(e=await t({request:this.request,response:e,event:this.event})||void 0,s=!0,!e)break;return s||e&&200!==e.status&&(e=void 0),e}}class v{constructor(t={}){this.cacheName=d(t.cacheName),this.plugins=t.plugins||[],this.fetchOptions=t.fetchOptions,this.matchOptions=t.matchOptions}handle(t){const[e]=this.handleAll(t);return e}handleAll(t){t instanceof FetchEvent&&(t={event:t,request:t.request});const e=t.event,s="string"==typeof t.request?new Request(t.request):t.request,n="params"in t?t.params:void 0,r=new m(this,{event:e,request:s,params:n}),i=this.q(r,s,e);return[i,this.U(i,r,s,e)]}async q(t,e,n){let r;await t.runCallbacks("handlerWillStart",{event:n,request:e});try{if(r=await this.L(e,t),!r||"error"===r.type)throw new s("no-response",{url:e.url})}catch(s){if(s instanceof Error)for(const i of t.iterateCallbacks("handlerDidError"))if(r=await i({error:s,event:n,request:e}),r)break;if(!r)throw s}for(const s of t.iterateCallbacks("handlerWillRespond"))r=await s({event:n,request:e,response:r});return r}async U(t,e,s,n){let r,i;try{r=await t}catch(i){}try{await e.runCallbacks("handlerDidRespond",{event:n,request:s,response:r}),await e.doneWaiting()}catch(t){t instanceof Error&&(i=t)}if(await e.runCallbacks("handlerDidComplete",{event:n,request:s,response:r,error:i}),e.destroy(),i)throw i}}function q(t,e){const s=e();return t.waitUntil(s),s}try{self["workbox:precaching:7.3.0"]&&_()}catch(t){}function U(t){if(!t)throw new s("add-to-cache-list-unexpected-type",{entry:t});if("string"==typeof t){const e=new URL(t,location.href);return{cacheKey:e.href,url:e.href}}const{revision:e,url:n}=t;if(!n)throw new s("add-to-cache-list-unexpected-type",{entry:t});if(!e){const t=new URL(n,location.href);return{cacheKey:t.href,url:t.href}}const r=new URL(n,location.href),i=new URL(n,location.href);return r.searchParams.set("__WB_REVISION__",e),{cacheKey:r.href,url:i.href}}class L{constructor(){this.updatedURLs=[],this.notUpdatedURLs=[],this.handlerWillStart=async({request:t,state:e})=>{e&&(e.originalRequest=t)},this.cachedResponseWillBeUsed=async({event:t,state:e,cachedResponse:s})=>{if("install"===t.type&&e&&e.originalRequest&&e.originalRequest instanceof Request){const t=e.originalRequest.url;s?this.notUpdatedURLs.push(t):this.updatedURLs.push(t)}return s}}}class b{constructor({precacheController:t}){this.cacheKeyWillBeUsed=async({request:t,params:e})=>{const s=(null==e?void 0:e.cacheKey)||this._.getCacheKeyForURL(t.url);return s?new Request(s,{headers:t.headers}):t},this._=t}}let E,C;async function x(t,e){let n=null;if(t.url){n=new URL(t.url).origin}if(n!==self.location.origin)throw new s("cross-origin-copy-response",{origin:n});const r=t.clone(),i={headers:new Headers(r.headers),status:r.status,statusText:r.statusText},o=e?e(i):i,c=function(){if(void 0===E){const t=new Response("");if("body"in t)try{new Response(t.body),E=!0}catch(t){E=!1}E=!1}return E}()?r.body:await r.blob();return new Response(c,o)}class O extends v{constructor(t={}){t.cacheName=w(t.cacheName),super(t),this.C=!1!==t.fallbackToNetwork,this.plugins.push(O.copyRedirectedCacheableResponsesPlugin)}async L(t,e){const s=await e.cacheMatch(t);return s||(e.event&&"install"===e.event.type?await this.O(t,e):await this.N(t,e))}async N(t,e){let n;const r=e.params||{};if(!this.C)throw new s("missing-precache-entry",{cacheName:this.cacheName,url:t.url});{const s=r.integrity,i=t.integrity,o=!i||i===s;n=await e.fetch(new Request(t,{integrity:"no-cors"!==t.mode?i||s:void 0})),s&&o&&"no-cors"!==t.mode&&(this.P(),await e.cachePut(t,n.clone()))}return n}async O(t,e){this.P();const n=await e.fetch(t);if(!await e.cachePut(t,n.clone()))throw new s("bad-precaching-response",{url:t.url,status:n.status});return n}P(){let t=null,e=0;for(const[s,n]of this.plugins.entries())n!==O.copyRedirectedCacheableResponsesPlugin&&(n===O.defaultPrecacheCacheabilityPlugin&&(t=s),n.cacheWillUpdate&&e++);0===e?this.plugins.push(O.defaultPrecacheCacheabilityPlugin):e>1&&null!==t&&this.plugins.splice(t,1)}}O.defaultPrecacheCacheabilityPlugin={cacheWillUpdate:async({response:t})=>!t||t.status>=400?null:t},O.copyRedirectedCacheableResponsesPlugin={cacheWillUpdate:async({response:t})=>t.redirected?await x(t):t};class N{constructor({cacheName:t,plugins:e=[],fallbackToNetwork:s=!0}={}){this.k=new Map,this.T=new Map,this.j=new Map,this.u=new O({cacheName:w(t),plugins:[...e,new b({precacheController:this})],fallbackToNetwork:s}),this.install=this.install.bind(this),this.activate=this.activate.bind(this)}get strategy(){return this.u}precache(t){this.addToCacheList(t),this.K||(self.addEventListener("install",this.install),self.addEventListener("activate",this.activate),this.K=!0)}addToCacheList(t){const e=[];for(const n of t){"string"==typeof n?e.push(n):n&&void 0===n.revision&&e.push(n.url);const{cacheKey:t,url:r}=U(n),i="string"!=typeof n&&n.revision?"reload":"default";if(this.k.has(r)&&this.k.get(r)!==t)throw new s("add-to-cache-list-conflicting-entries",{firstEntry:this.k.get(r),secondEntry:t});if("string"!=typeof n&&n.integrity){if(this.j.has(t)&&this.j.get(t)!==n.integrity)throw new s("add-to-cache-list-conflicting-integrities",{url:r});this.j.set(t,n.integrity)}if(this.k.set(r,t),this.T.set(r,i),e.length>0){const t=`Workbox is precaching URLs without revision info: ${e.join(", ")}\nThis is generally NOT safe. Learn more at https://bit.ly/wb-precache`;console.warn(t)}}}install(t){return q(t,async()=>{const e=new L;this.strategy.plugins.push(e);for(const[e,s]of this.k){const n=this.j.get(s),r=this.T.get(e),i=new Request(e,{integrity:n,cache:r,credentials:"same-origin"});await Promise.all(this.strategy.handleAll({params:{cacheKey:s},request:i,event:t}))}const{updatedURLs:s,notUpdatedURLs:n}=e;return{updatedURLs:s,notUpdatedURLs:n}})}activate(t){return q(t,async()=>{const t=await self.caches.open(this.strategy.cacheName),e=await t.keys(),s=new Set(this.k.values()),n=[];for(const r of e)s.has(r.url)||(await t.delete(r),n.push(r.url));return{deletedURLs:n}})}getURLsToCacheKeys(){return this.k}getCachedURLs(){return[...this.k.keys()]}getCacheKeyForURL(t){const e=new URL(t,location.href);return this.k.get(e.href)}getIntegrityForCacheKey(t){return this.j.get(t)}async matchPrecache(t){const e=t instanceof Request?t.url:t,s=this.getCacheKeyForURL(e);if(s){return(await self.caches.open(this.strategy.cacheName)).match(s)}}createHandlerBoundToURL(t){const e=this.getCacheKeyForURL(t);if(!e)throw new s("non-precached-url",{url:t});return s=>(s.request=new Request(t),s.params=Object.assign({cacheKey:e},s.params),this.strategy.handle(s))}}const P=()=>(C||(C=new N),C);class k extends r{constructor(t,e){super(({request:s})=>{const n=t.getURLsToCacheKeys();for(const r of function*(t,{ignoreURLParametersMatching:e=[/^utm_/,/^fbclid$/],directoryIndex:s="index.html",cleanURLs:n=!0,urlManipulation:r}={}){const i=new URL(t,location.href);i.hash="",yield i.href;const o=function(t,e=[]){for(const s of[...t.searchParams.keys()])e.some(t=>t.test(s))&&t.searchParams.delete(s);return t}(i,e);if(yield o.href,s&&o.pathname.endsWith("/")){const t=new URL(o.href);t.pathname+=s,yield t.href}if(n){const t=new URL(o.href);t.pathname+=".html",yield t.href}if(r){const t=r({url:i});for(const e of t)yield e.href}}(s.url,e)){const e=n.get(r);if(e){return{cacheKey:e,integrity:t.getIntegrityForCacheKey(e)}}}},t.strategy)}}t.NavigationRoute=class extends r{constructor(t,{allowlist:e=[/./],denylist:s=[]}={}){super(t=>this.W(t),t),this.M=e,this.S=s}W({url:t,request:e}){if(e&&"navigate"!==e.mode)return!1;const s=t.pathname+t.search;for(const t of this.S)if(t.test(s))return!1;return!!this.M.some(t=>t.test(s))}},t.NetworkOnly=class extends v{constructor(t={}){super(t),this.D=t.networkTimeoutSeconds||0}async L(t,e){let n,r;try{const s=[e.fetch(t)];if(this.D){const t=u(1e3*this.D);s.push(t)}if(r=await Promise.race(s),!r)throw new Error(`Timed out the network response after ${this.D} seconds.`)}catch(t){t instanceof Error&&(n=t)}if(!r)throw new s("no-response",{url:t.url,error:n});return r}},t.cleanupOutdatedCaches=function(){self.addEventListener("activate",t=>{const e=w();t.waitUntil((async(t,e="-precache-")=>{const s=(await self.caches.keys()).filter(s=>s.includes(e)&&s.includes(self.registration.scope)&&s!==t);return await Promise.all(s.map(t=>self.caches.delete(t))),s})(e).then(t=>{}))})},t.clientsClaim=function(){self.addEventListener("activate",()=>self.clients.claim())},t.createHandlerBoundToURL=function(t){return P().createHandlerBoundToURL(t)},t.precacheAndRoute=function(t,e){!function(t){P().precache(t)}(t),function(t){const e=P();h(new k(e,t))}(e)},t.registerRoute=h});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hienlh/ppm",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Personal Project Manager — mobile-first web IDE with AI assistance",
|
|
5
5
|
"module": "src/index.ts",
|
|
6
6
|
"type": "module",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"build": "bun run build:web && bun build src/index.ts --compile --outfile dist/ppm",
|
|
15
15
|
"start": "bun run src/index.ts start",
|
|
16
16
|
"typecheck": "bunx tsc --noEmit",
|
|
17
|
+
"prepublishOnly": "bun run build:web",
|
|
17
18
|
"postinstall": "node node_modules/ccburn/scripts/postinstall.js"
|
|
18
19
|
},
|
|
19
20
|
"devDependencies": {
|
package/src/server/index.ts
CHANGED
|
@@ -114,11 +114,25 @@ export async function startServer(options: {
|
|
|
114
114
|
} as Parameters<typeof Bun.serve>[0] extends { websocket?: infer W } ? W : never,
|
|
115
115
|
});
|
|
116
116
|
|
|
117
|
-
console.log(
|
|
118
|
-
console.log(`
|
|
117
|
+
console.log(`\n PPM v0.1.2 ready\n`);
|
|
118
|
+
console.log(` ➜ Local: http://localhost:${server.port}/`);
|
|
119
|
+
|
|
120
|
+
// List all network interfaces
|
|
121
|
+
const { networkInterfaces } = await import("node:os");
|
|
122
|
+
const nets = networkInterfaces();
|
|
123
|
+
for (const name of Object.keys(nets)) {
|
|
124
|
+
for (const net of nets[name] ?? []) {
|
|
125
|
+
if (net.family === "IPv4" && !net.internal) {
|
|
126
|
+
console.log(` ➜ Network: http://${net.address}:${server.port}/`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
console.log(`\n Auth: ${configService.get("auth").enabled ? "enabled" : "disabled"}`);
|
|
119
132
|
if (configService.get("auth").enabled) {
|
|
120
|
-
console.log(`Token: ${configService.get("auth").token}`);
|
|
133
|
+
console.log(` Token: ${configService.get("auth").token}`);
|
|
121
134
|
}
|
|
135
|
+
console.log();
|
|
122
136
|
}
|
|
123
137
|
|
|
124
138
|
// Internal entry point for daemon child process
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: PPM test conventions and gotchas
|
|
3
|
-
description: Key patterns, pitfalls, and setup details for writing tests in the PPM project
|
|
4
|
-
type: project
|
|
5
|
-
---
|
|
6
|
-
|
|
7
|
-
## Test runner: `bun test` (Jest-compatible API from `bun:test`)
|
|
8
|
-
|
|
9
|
-
## Test structure
|
|
10
|
-
- `tests/setup.ts` — shared helpers: `createTempDir`, `cleanupDir`, `createTempGitRepo`, `buildTestApp`
|
|
11
|
-
- `tests/unit/services/` — unit tests for ConfigService, ProjectService, FileService, GitService
|
|
12
|
-
- `tests/integration/api/` — integration tests using `app.request()` (no real server needed)
|
|
13
|
-
|
|
14
|
-
## Critical gotchas
|
|
15
|
-
|
|
16
|
-
### ppm.yaml in CWD
|
|
17
|
-
The project root has a real `ppm.yaml` with `port: 5555`. `ConfigService.load(missingPath)` falls through to `LOCAL_CONFIG = "ppm.yaml"` in CWD when the given path doesn't exist. Always write an actual file before calling `load()` to avoid picking up this real config.
|
|
18
|
-
|
|
19
|
-
### Global configService in git routes
|
|
20
|
-
`src/server/routes/git.ts` imports and uses the global `configService` singleton (not injected). Integration tests for git API must mutate `configService.config.projects` directly to register the test repo. Restore to `[]` in `afterEach`.
|
|
21
|
-
|
|
22
|
-
### ConfigService.load() fallback behavior
|
|
23
|
-
Candidates checked in order: explicit path → PPM_CONFIG env → LOCAL_CONFIG (ppm.yaml) → HOME_CONFIG (~/.ppm/config.yaml). A missing explicit path does NOT stop the fallback chain.
|
|
24
|
-
|
|
25
|
-
### buildTestApp in setup.ts
|
|
26
|
-
Overrides `configService.save = () => {}` (no-op) to prevent tests writing to disk. Injects config directly by mutating private fields via `as unknown as`.
|
|
27
|
-
|
|
28
|
-
### Real git repos for git tests
|
|
29
|
-
`createTempGitRepo()` uses `Bun.spawn` with git env vars (author name/email) to create a real repo with an initial commit. No mocks for git operations.
|
|
30
|
-
|
|
31
|
-
**Why:** Tests must use real implementations — no fakes/mocks that diverge from production behavior.
|
|
32
|
-
**How to apply:** Always use `createTempGitRepo` for anything touching GitService or git API routes.
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
name: Release
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
tags: ['v*']
|
|
6
|
-
|
|
7
|
-
jobs:
|
|
8
|
-
build:
|
|
9
|
-
strategy:
|
|
10
|
-
matrix:
|
|
11
|
-
include:
|
|
12
|
-
- os: ubuntu-latest
|
|
13
|
-
target: bun-linux-x64
|
|
14
|
-
artifact: ppm-linux-x64
|
|
15
|
-
- os: macos-latest
|
|
16
|
-
target: bun-darwin-arm64
|
|
17
|
-
artifact: ppm-darwin-arm64
|
|
18
|
-
- os: macos-13
|
|
19
|
-
target: bun-darwin-x64
|
|
20
|
-
artifact: ppm-darwin-x64
|
|
21
|
-
|
|
22
|
-
runs-on: ${{ matrix.os }}
|
|
23
|
-
steps:
|
|
24
|
-
- uses: actions/checkout@v4
|
|
25
|
-
- uses: oven-sh/setup-bun@v2
|
|
26
|
-
- run: bun install
|
|
27
|
-
- run: bun run build:web
|
|
28
|
-
- run: bun build src/index.ts --compile --target=${{ matrix.target }} --outfile=dist/${{ matrix.artifact }}
|
|
29
|
-
- uses: actions/upload-artifact@v4
|
|
30
|
-
with:
|
|
31
|
-
name: ${{ matrix.artifact }}
|
|
32
|
-
path: dist/${{ matrix.artifact }}
|
|
33
|
-
|
|
34
|
-
release:
|
|
35
|
-
needs: build
|
|
36
|
-
runs-on: ubuntu-latest
|
|
37
|
-
permissions:
|
|
38
|
-
contents: write
|
|
39
|
-
steps:
|
|
40
|
-
- uses: actions/download-artifact@v4
|
|
41
|
-
- uses: softprops/action-gh-release@v2
|
|
42
|
-
with:
|
|
43
|
-
files: |
|
|
44
|
-
ppm-linux-x64/ppm-linux-x64
|
|
45
|
-
ppm-darwin-arm64/ppm-darwin-arm64
|
|
46
|
-
ppm-darwin-x64/ppm-darwin-x64
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
# Phase 1: Project Skeleton + Shared Types
|
|
2
|
-
|
|
3
|
-
**Owner:** Lead
|
|
4
|
-
**Priority:** Critical
|
|
5
|
-
**Depends on:** None
|
|
6
|
-
**Effort:** Small
|
|
7
|
-
|
|
8
|
-
## Overview
|
|
9
|
-
|
|
10
|
-
Initialize monorepo, install dependencies, create shared types, config files. This unblocks all other phases.
|
|
11
|
-
|
|
12
|
-
## Steps
|
|
13
|
-
|
|
14
|
-
1. **Init Bun project**
|
|
15
|
-
```bash
|
|
16
|
-
bun init
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
2. **Install backend dependencies**
|
|
20
|
-
```bash
|
|
21
|
-
bun add hono commander js-yaml simple-git @anthropic-ai/claude-agent-sdk
|
|
22
|
-
bun add -d @types/node typescript
|
|
23
|
-
```
|
|
24
|
-
|
|
25
|
-
3. **Install frontend dependencies**
|
|
26
|
-
```bash
|
|
27
|
-
bun add react react-dom zustand @tanstack/react-query
|
|
28
|
-
bun add -d vite @vitejs/plugin-react tailwindcss @tailwindcss/vite vite-plugin-pwa
|
|
29
|
-
bun add codemirror @codemirror/lang-javascript @codemirror/lang-typescript @codemirror/lang-python @codemirror/lang-html @codemirror/lang-css @codemirror/lang-json @codemirror/lang-markdown @codemirror/autocomplete @codemirror/merge @codemirror/theme-one-dark @uiw/react-codemirror
|
|
30
|
-
bun add @xterm/xterm @xterm/addon-fit @xterm/addon-web-links
|
|
31
|
-
bun add diff2html react-resizable-panels lucide-react
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
4. **Init shadcn/ui**
|
|
35
|
-
```bash
|
|
36
|
-
bunx --bun shadcn@latest init
|
|
37
|
-
bunx --bun shadcn@latest add button dialog dropdown-menu context-menu input tabs scroll-area tooltip separator sonner
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
5. **Create config files**
|
|
41
|
-
- `tsconfig.json` — strict, paths alias `@/` → `src/web/`
|
|
42
|
-
- `vite.config.ts` — React plugin, Tailwind, PWA plugin, build output to `dist/web`
|
|
43
|
-
- `tailwind.config.ts` — shadcn/ui preset, mobile-first
|
|
44
|
-
- `bunfig.toml` — Bun config
|
|
45
|
-
- `ppm.example.yaml` — example config
|
|
46
|
-
- `.env.example` — `ANTHROPIC_API_KEY=`
|
|
47
|
-
- `.gitignore`
|
|
48
|
-
|
|
49
|
-
6. **Create shared types** (`src/types/`)
|
|
50
|
-
- `config.ts` — PpmConfig, AuthConfig, ProjectConfig, AIProviderConfig
|
|
51
|
-
- `project.ts` — Project, ProjectInfo
|
|
52
|
-
- `git.ts` — GitCommit, GitBranch, GitStatus, GitGraphData, GitDiffResult, GitFileChange
|
|
53
|
-
- `chat.ts` — AIProvider interface, ChatEvent, SessionConfig, SessionInfo, ToolApprovalRequest
|
|
54
|
-
- `terminal.ts` — TerminalSession, TerminalResize
|
|
55
|
-
- `api.ts` — API request/response wrappers
|
|
56
|
-
|
|
57
|
-
7. **Create entry point** `src/index.ts` — minimal Commander.js setup with `start` command placeholder
|
|
58
|
-
|
|
59
|
-
8. **Create README.md** with project description, setup instructions
|
|
60
|
-
|
|
61
|
-
9. **Create CLAUDE.md** with project conventions
|
|
62
|
-
|
|
63
|
-
10. **Verify build**
|
|
64
|
-
```bash
|
|
65
|
-
bun run src/index.ts --help
|
|
66
|
-
```
|
|
67
|
-
|
|
68
|
-
## Files to Create
|
|
69
|
-
|
|
70
|
-
- `package.json`, `tsconfig.json`, `vite.config.ts`, `tailwind.config.ts`, `bunfig.toml`
|
|
71
|
-
- `ppm.example.yaml`, `.env.example`, `.gitignore`
|
|
72
|
-
- `src/index.ts`
|
|
73
|
-
- `src/types/*.ts` (6 files)
|
|
74
|
-
- `README.md`, `CLAUDE.md`, `LICENSE`
|
|
75
|
-
|
|
76
|
-
## Success Criteria
|
|
77
|
-
|
|
78
|
-
- [x] `bun run src/index.ts --help` shows CLI help
|
|
79
|
-
- [x] `bun run --hot src/web/main.tsx` (via vite) starts dev server
|
|
80
|
-
- [x] All shared types compile without errors
|
|
81
|
-
- [x] shadcn/ui components installed and importable
|
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
# Phase 2: Backend Core (Server + CLI + Config)
|
|
2
|
-
|
|
3
|
-
**Owner:** backend-dev
|
|
4
|
-
**Priority:** Critical
|
|
5
|
-
**Depends on:** Phase 1
|
|
6
|
-
**Effort:** Medium
|
|
7
|
-
|
|
8
|
-
## Overview
|
|
9
|
-
|
|
10
|
-
Hono HTTP server, WebSocket upgrade, config loading, auth middleware, static file serving. CLI `init`, `start`, `stop`, `open` commands.
|
|
11
|
-
|
|
12
|
-
## Key Insights
|
|
13
|
-
|
|
14
|
-
- Hono on Bun has built-in WebSocket support via `Bun.serve`
|
|
15
|
-
- Config loaded from `ppm.yaml` via js-yaml, validated at startup
|
|
16
|
-
- Auth = simple Bearer token header check
|
|
17
|
-
- Static files = serve Vite build output from `dist/web/`
|
|
18
|
-
|
|
19
|
-
## Files to Create/Modify
|
|
20
|
-
|
|
21
|
-
```
|
|
22
|
-
src/
|
|
23
|
-
├── server/
|
|
24
|
-
│ ├── index.ts # Hono app, mount routes, WS upgrade
|
|
25
|
-
│ ├── middleware/auth.ts # Token auth
|
|
26
|
-
│ ├── routes/static.ts # Serve SPA with fallback to index.html
|
|
27
|
-
│ └── routes/projects.ts # GET /api/projects, POST /api/projects
|
|
28
|
-
├── services/
|
|
29
|
-
│ ├── config.service.ts # Load/save ppm.yaml
|
|
30
|
-
│ └── project.service.ts # Project CRUD (add/remove/list)
|
|
31
|
-
├── cli/
|
|
32
|
-
│ ├── index.ts # Commander.js program setup
|
|
33
|
-
│ ├── commands/init.ts # Scan .git folders, interactive setup
|
|
34
|
-
│ ├── commands/start.ts # Start Hono server (+ daemon mode)
|
|
35
|
-
│ ├── commands/stop.ts # Kill daemon by PID file
|
|
36
|
-
│ ├── commands/open.ts # Open browser to http://localhost:PORT
|
|
37
|
-
│ └── utils/project-resolver.ts # CWD detect + -p flag
|
|
38
|
-
└── index.ts # Wire CLI → commands
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
## Implementation Steps
|
|
42
|
-
|
|
43
|
-
### 1. Config Service
|
|
44
|
-
```typescript
|
|
45
|
-
// config.service.ts
|
|
46
|
-
class ConfigService {
|
|
47
|
-
private config: PpmConfig;
|
|
48
|
-
load(path?: string): PpmConfig // Default: ~/.ppm/config.yaml or ./ppm.yaml
|
|
49
|
-
save(): void
|
|
50
|
-
get<K extends keyof PpmConfig>(key: K): PpmConfig[K]
|
|
51
|
-
set<K extends keyof PpmConfig>(key: K, value: PpmConfig[K]): void
|
|
52
|
-
}
|
|
53
|
-
```
|
|
54
|
-
- Search order: `--config` flag → `./ppm.yaml` → `~/.ppm/config.yaml`
|
|
55
|
-
- Create default config on first run
|
|
56
|
-
|
|
57
|
-
### 2. Project Service
|
|
58
|
-
```typescript
|
|
59
|
-
class ProjectService {
|
|
60
|
-
constructor(private config: ConfigService)
|
|
61
|
-
list(): ProjectInfo[]
|
|
62
|
-
add(path: string, name?: string): void
|
|
63
|
-
remove(nameOrPath: string): void
|
|
64
|
-
resolve(nameOrPath?: string): Project // CWD or -p flag
|
|
65
|
-
scanForGitRepos(dir: string): string[] // Find .git folders recursively
|
|
66
|
-
}
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
### 3. Hono Server
|
|
70
|
-
```typescript
|
|
71
|
-
// server/index.ts
|
|
72
|
-
const app = new Hono()
|
|
73
|
-
app.use('/api/*', authMiddleware)
|
|
74
|
-
app.route('/api/projects', projectRoutes)
|
|
75
|
-
// WS upgrade handled at Bun.serve level
|
|
76
|
-
// Static files: serve dist/web/ with SPA fallback
|
|
77
|
-
```
|
|
78
|
-
|
|
79
|
-
### 4. Auth Middleware
|
|
80
|
-
- Check `Authorization: Bearer <token>` header
|
|
81
|
-
- Skip auth if `config.auth.enabled === false`
|
|
82
|
-
- Return 401 on failure
|
|
83
|
-
|
|
84
|
-
**Auth flow (minimal):**
|
|
85
|
-
- Token stored in `ppm.yaml` → `auth.token` field
|
|
86
|
-
- Generated on `ppm init` (random 32-char hex)
|
|
87
|
-
- Browser: on first visit, if `auth.enabled === true`, show password input screen
|
|
88
|
-
- User enters token → stored in localStorage → sent as Bearer header on all API calls
|
|
89
|
-
- No user/password DB — single shared token from config
|
|
90
|
-
- Config example:
|
|
91
|
-
```yaml
|
|
92
|
-
auth:
|
|
93
|
-
enabled: true
|
|
94
|
-
token: "a1b2c3..." # auto-generated, user can change
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
**Frontend auth screen** (`src/web/components/auth/login-screen.tsx`):
|
|
98
|
-
- Full-screen centered card: "Enter Access Token" + input + submit
|
|
99
|
-
- On submit: store token in localStorage, redirect to app
|
|
100
|
-
- On 401 from any API call: clear localStorage, show login screen
|
|
101
|
-
|
|
102
|
-
### 5. CLI Commands
|
|
103
|
-
- `ppm init` — interactive: scan parent dir for .git, prompt to add, create config
|
|
104
|
-
- `ppm start` — start Hono server, optionally daemonize (`-d` flag → detach process, write PID to `~/.ppm/ppm.pid`)
|
|
105
|
-
- `ppm stop` — read PID file, kill process
|
|
106
|
-
- `ppm open` — `open http://localhost:${port}` (macOS) / `xdg-open` (Linux)
|
|
107
|
-
|
|
108
|
-
### 6. Project Resolver
|
|
109
|
-
```typescript
|
|
110
|
-
function resolveProject(options: { project?: string }): Project {
|
|
111
|
-
if (options.project) return projectService.resolve(options.project);
|
|
112
|
-
const cwd = process.cwd();
|
|
113
|
-
const match = projectService.list().find(p => cwd.startsWith(p.path));
|
|
114
|
-
if (match) return match;
|
|
115
|
-
throw new Error('Not in a registered project. Use -p <name>');
|
|
116
|
-
}
|
|
117
|
-
```
|
|
118
|
-
|
|
119
|
-
### 7. Shared Project Resolver (`src/server/helpers/resolve-project.ts`)
|
|
120
|
-
|
|
121
|
-
**[V2 FIX]** All API routes must resolve project by NAME first, fallback to path:
|
|
122
|
-
```typescript
|
|
123
|
-
export function resolveProjectPath(nameOrPath: string): string {
|
|
124
|
-
const projects = configService.get("projects");
|
|
125
|
-
const byName = projects.find(p => p.name === nameOrPath);
|
|
126
|
-
if (byName) return resolve(byName.path);
|
|
127
|
-
const abs = resolve(nameOrPath);
|
|
128
|
-
const allowed = projects.some(p => abs === p.path || abs.startsWith(p.path + "/"));
|
|
129
|
-
if (!allowed) throw new Error(`Project not found: ${nameOrPath}`);
|
|
130
|
-
return abs;
|
|
131
|
-
}
|
|
132
|
-
```
|
|
133
|
-
Import this in every route file (files.ts, git.ts, projects.ts).
|
|
134
|
-
|
|
135
|
-
## Success Criteria
|
|
136
|
-
|
|
137
|
-
- [ ] `ppm init` scans current dir, creates config file with auto-generated auth token
|
|
138
|
-
- [ ] `ppm start` starts HTTP server on configured port
|
|
139
|
-
- [ ] `ppm start -d` runs as daemon, writes PID file; `ppm stop` reads PID and kills process
|
|
140
|
-
- [ ] `GET /api/projects` with valid Bearer token returns project list as `{ ok: true, data: [...] }`
|
|
141
|
-
- [ ] `GET /api/projects` without token returns 401 `{ ok: false, error: "Unauthorized" }`
|
|
142
|
-
- [ ] `GET /api/projects` with `auth.enabled: false` in config returns data without token
|
|
143
|
-
- [ ] `ppm open` opens `http://localhost:<port>` in default browser
|
|
144
|
-
- [ ] `resolveProjectPath("ppm")` returns correct filesystem path from config
|
|
145
|
-
- [ ] `resolveProjectPath("nonexistent")` throws descriptive error
|
|
146
|
-
- [ ] Config service loads from `./ppm.yaml` → `~/.ppm/config.yaml` fallback chain
|
|
147
|
-
- [ ] Config service creates default config if none exists
|
|
148
|
-
- [ ] Static route serves `dist/web/index.html` for all non-API paths (SPA fallback)
|