| var GitHubCommands = { | |
| help: function() { | |
| return [ | |
| 'ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ', | |
| 'β GITHUB-NATIVE β COMMANDS β', | |
| 'β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£', | |
| 'β GitHubHelp; β show this β', | |
| 'β GitHubLogin; β paste GitHub token β', | |
| 'β GitHubLogout; β clear token β', | |
| 'β GitHubStatus; β check auth status β', | |
| 'β CreateInvertedRepo "name"; β create agent repo β', | |
| 'β CreateRepoFromTemplate "name"; β create from template β', | |
| 'β StapleRemoteRepo "owner/repo"; β staple remote repo β', | |
| 'β VerifyRemoteRepo "owner/repo"; β verify remote staple β', | |
| 'β β', | |
| 'β AUTH: Token stored in sessionStorage ONLY. β', | |
| 'β Never committed to repo or Woz Vault. β', | |
| 'ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ' | |
| ].join('\n'); | |
| }, | |
| login: function(args) { | |
| var token = args ? args[0] : ''; | |
| if (!token) return { output: 'Usage: GitHubLogin "ghp_your_token";\n\nToken stored in sessionStorage only.\nNever committed to repo or Woz Vault.', type: 'error' }; | |
| if (!token.startsWith('ghp_') && !token.startsWith('github_pat_')) { | |
| return { output: 'β WARNING: Token does not look like a GitHub personal access token.\nExpected format: ghp_xxx or github_pat_xxx\nProceed anyway? (token stored in sessionStorage only)', type: 'error' }; | |
| } | |
| GitHubAuth.setToken(token); | |
| WozVault.writeAuditEvent({ type: 'GITHUB_LOGIN', agent: 'USER' }); | |
| return { output: 'GitHub authenticated β\nToken: SESSION_ONLY\nβ Never committed to repo or Woz Vault.', type: 'success' }; | |
| }, | |
| logout: function() { | |
| GitHubAuth.clearToken(); | |
| return { output: 'GitHub token cleared.', type: 'success' }; | |
| }, | |
| status: async function() { | |
| var st = GitHubAuth.status(); | |
| var validation = st.authenticated ? await GitHubAuth.validateToken() : null; | |
| return { | |
| output: [ | |
| 'ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ', | |
| 'β GITHUB STATUS β', | |
| 'β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£', | |
| 'β AUTH: ' + (st.authenticated ? 'AUTHENTICATED β' : 'AUTH REQUIRED').padEnd(45) + 'β', | |
| 'β USER: ' + (validation && validation.user ? validation.user : 'none').padEnd(45) + 'β', | |
| 'β STORAGE: SESSION ONLY'.padEnd(45) + 'β', | |
| 'β TOKEN: ' + (st.authenticated ? 'SET (not shown)' : 'NOT SET').padEnd(45) + 'β', | |
| 'β SCOPES: ' + (validation && validation.scopes ? validation.scopes.substring(0, 45) : 'unknown').padEnd(45) + 'β', | |
| 'ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ' | |
| ].join('\n'), | |
| type: 'success' | |
| }; | |
| }, | |
| createRepo: async function(args) { | |
| var name = args ? args[0] : ''; | |
| if (!name) return { output: 'Usage: CreateInvertedRepo "repo-name";', type: 'error' }; | |
| var type = args[1] || 'agent'; | |
| var result = await RepoBuilder.createInvertedRepo(name, type); | |
| return { output: RepoBuilder.render(result), type: result.error ? 'error' : 'success' }; | |
| }, | |
| createFromTemplate: async function(args) { | |
| var name = args ? args[0] : ''; | |
| if (!name) return { output: 'Usage: CreateRepoFromTemplate "repo-name";', type: 'error' }; | |
| var types = InvertedRepoTemplate.listTypes(); | |
| var typeList = types.map(function(t) { return t.key + ' β ' + t.desc; }).join('\n'); | |
| var result = await RepoBuilder.createInvertedRepo(name, args[1] || 'agent'); | |
| return { output: RepoBuilder.render(result), type: result.error ? 'error' : 'success' }; | |
| }, | |
| stapleRemote: async function(args) { | |
| var full = args ? args[0] : ''; | |
| if (!full || full.indexOf('/') < 0) return { output: 'Usage: StapleRemoteRepo "owner/repo";', type: 'error' }; | |
| var parts = full.split('/'); | |
| try { | |
| var staple = await RepoStapleWriter.writeStaple(parts[0], parts[1]); | |
| return { output: 'Remote staple written β\nRepo: ' + full + '\nSeal: ' + (staple.pageSeal || 'none'), type: 'success' }; | |
| } catch (e) { | |
| return { output: 'ERROR: ' + e.message, type: 'error' }; | |
| } | |
| }, | |
| verifyRemote: async function(args) { | |
| var full = args ? args[0] : ''; | |
| if (!full || full.indexOf('/') < 0) return { output: 'Usage: VerifyRemoteRepo "owner/repo";', type: 'error' }; | |
| var parts = full.split('/'); | |
| var result = await RepoStapleWriter.verifyRemote(parts[0], parts[1]); | |
| if (result.error) return { output: 'ERROR: ' + result.error, type: 'error' }; | |
| return { | |
| output: [ | |
| 'ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ', | |
| 'β REMOTE STAPLE VERIFICATION β', | |
| 'β βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ£', | |
| 'β REPO: ' + full.padEnd(45) + 'β', | |
| 'β VERIFIED: ' + (result.verified ? 'YES β' : 'NO').padEnd(45) + 'β', | |
| 'β CHECKS: ' + (result.passed + '/' + result.total).padEnd(45) + 'β', | |
| 'β VERSION: ' + (result.staple ? result.staple.version : 'unknown').padEnd(45) + 'β', | |
| 'β SEALED: ' + (result.staple ? result.staple.pageSeal.substring(0, 45) : 'none').padEnd(45) + 'β', | |
| 'ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ' | |
| ].join('\n'), | |
| type: result.verified ? 'success' : 'error' | |
| }; | |
| } | |
| }; | |