starmux 0.13.0 → 0.14.0
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/LICENSE +1 -1
- package/README.md +20 -30
- package/dist/src/access-control.js +1 -2
- package/dist/src/access-dashboard.js +2 -3
- package/dist/src/account-access-policy.js +54 -0
- package/dist/src/authorized-workspace-roots.js +0 -1
- package/dist/src/batch-read-policy.js +30 -0
- package/dist/src/cli/instances.js +6 -175
- package/dist/src/cli/oauth.js +0 -1
- package/dist/src/cli/starmux-status.js +10 -14
- package/dist/src/cli/starmux-supervisor.js +0 -1
- package/dist/src/cli/starmux.js +13 -25
- package/dist/src/config-schemas.js +0 -9
- package/dist/src/configured-mcp-upstreams.js +0 -1
- package/dist/src/contracts.js +0 -1
- package/dist/src/current-permission-probe.js +0 -1
- package/dist/src/dc-workspace-http.js +57 -33
- package/dist/src/deny-dashboard.js +2 -3
- package/dist/src/desktop-commander-facade.js +4 -4
- package/dist/src/explicit-deny-rules.js +2 -3
- package/dist/src/global-core-control.js +2 -3
- package/dist/src/home-write-sandbox.js +0 -1
- package/dist/src/http-host-policy.js +20 -0
- package/dist/src/instance-runtime.js +3 -3
- package/dist/src/instance-store.js +28 -22
- package/dist/src/instance-worker.js +2 -3
- package/dist/src/invocation.js +1 -2
- package/dist/src/local-desktop-read-probe.js +5 -88
- package/dist/src/managed-workspace-policy.js +38 -4
- package/dist/src/mcp-results.js +0 -1
- package/dist/src/mcp-upstream-router.js +0 -1
- package/dist/src/oauth-keycloak.js +0 -1
- package/dist/src/oauth-resource.js +0 -1
- package/dist/src/ops-dashboard.js +2 -179
- package/dist/src/permissions-dashboard.js +3 -4
- package/dist/src/platform.js +3 -4
- package/dist/src/privacy-diagnostics.js +0 -1
- package/dist/src/private-mcp-activity.js +0 -1
- package/dist/src/private-store-lock.js +0 -1
- package/dist/src/project-dev-presets.js +0 -1
- package/dist/src/project-git-workflow.js +0 -1
- package/dist/src/project-workspace-policy.js +10 -6
- package/dist/src/runtime-identity.js +0 -14
- package/dist/src/runtime-paths.js +0 -3
- package/dist/src/tool-dispatch.js +45 -46
- package/dist/src/validation.js +0 -1
- package/dist/src/workspace-grants.js +1 -2
- package/package.json +13 -17
- package/scripts/prepare.mjs +1 -1
- package/CONTRIBUTING.md +0 -18
- package/SECURITY.md +0 -7
- package/app/README.md +0 -29
- package/dist/src/access-control.js.map +0 -1
- package/dist/src/access-dashboard.js.map +0 -1
- package/dist/src/authorized-workspace-roots.js.map +0 -1
- package/dist/src/cli/access.js +0 -53
- package/dist/src/cli/access.js.map +0 -1
- package/dist/src/cli/community-remote-revoke.js +0 -32
- package/dist/src/cli/community-remote-revoke.js.map +0 -1
- package/dist/src/cli/instances.js.map +0 -1
- package/dist/src/cli/live-home-settings.js +0 -35
- package/dist/src/cli/live-home-settings.js.map +0 -1
- package/dist/src/cli/mac-mcp-gateway.js +0 -257
- package/dist/src/cli/mac-mcp-gateway.js.map +0 -1
- package/dist/src/cli/oauth.js.map +0 -1
- package/dist/src/cli/permissions-owner.js +0 -27
- package/dist/src/cli/permissions-owner.js.map +0 -1
- package/dist/src/cli/service-setup.js +0 -26
- package/dist/src/cli/service-setup.js.map +0 -1
- package/dist/src/cli/setup-wizard.js +0 -149
- package/dist/src/cli/setup-wizard.js.map +0 -1
- package/dist/src/cli/starmux-status.js.map +0 -1
- package/dist/src/cli/starmux-supervisor.js.map +0 -1
- package/dist/src/cli/starmux.js.map +0 -1
- package/dist/src/cli/verify-setup.js +0 -53
- package/dist/src/cli/verify-setup.js.map +0 -1
- package/dist/src/community-remote-revocations.js +0 -135
- package/dist/src/community-remote-revocations.js.map +0 -1
- package/dist/src/config-schemas.js.map +0 -1
- package/dist/src/configured-mcp-upstreams.js.map +0 -1
- package/dist/src/contracts.js.map +0 -1
- package/dist/src/current-permission-probe.js.map +0 -1
- package/dist/src/dc-workspace-http.js.map +0 -1
- package/dist/src/deny-dashboard.js.map +0 -1
- package/dist/src/desktop-commander-facade.js.map +0 -1
- package/dist/src/explicit-deny-rules.js.map +0 -1
- package/dist/src/gateway-status-format.js +0 -66
- package/dist/src/gateway-status-format.js.map +0 -1
- package/dist/src/global-core-control.js.map +0 -1
- package/dist/src/home-write-sandbox.js.map +0 -1
- package/dist/src/instance-migration.js +0 -138
- package/dist/src/instance-migration.js.map +0 -1
- package/dist/src/instance-runtime.js.map +0 -1
- package/dist/src/instance-store.js.map +0 -1
- package/dist/src/instance-worker.js.map +0 -1
- package/dist/src/invocation.js.map +0 -1
- package/dist/src/live-profile-home-settings.js +0 -80
- package/dist/src/live-profile-home-settings.js.map +0 -1
- package/dist/src/local-desktop-read-probe.js.map +0 -1
- package/dist/src/managed-workspace-policy.js.map +0 -1
- package/dist/src/mcp-results.js.map +0 -1
- package/dist/src/mcp-upstream-router.js.map +0 -1
- package/dist/src/oauth-keycloak.js.map +0 -1
- package/dist/src/oauth-resource.js.map +0 -1
- package/dist/src/operator-cli.js +0 -559
- package/dist/src/operator-cli.js.map +0 -1
- package/dist/src/ops-dashboard.js.map +0 -1
- package/dist/src/permissions-dashboard.js.map +0 -1
- package/dist/src/platform.js.map +0 -1
- package/dist/src/privacy-diagnostics.js.map +0 -1
- package/dist/src/private-mcp-activity.js.map +0 -1
- package/dist/src/private-store-lock.js.map +0 -1
- package/dist/src/project-dev-presets.js.map +0 -1
- package/dist/src/project-git-workflow.js.map +0 -1
- package/dist/src/project-workspace-policy.js.map +0 -1
- package/dist/src/read-scope.js +0 -44
- package/dist/src/read-scope.js.map +0 -1
- package/dist/src/release1-onboarding.js +0 -120
- package/dist/src/release1-onboarding.js.map +0 -1
- package/dist/src/release1-service.js +0 -131
- package/dist/src/release1-service.js.map +0 -1
- package/dist/src/remote-auth.js +0 -47
- package/dist/src/remote-auth.js.map +0 -1
- package/dist/src/runtime-identity.js.map +0 -1
- package/dist/src/runtime-paths.js.map +0 -1
- package/dist/src/starmux-migration.js +0 -172
- package/dist/src/starmux-migration.js.map +0 -1
- package/dist/src/tool-dispatch.js.map +0 -1
- package/dist/src/validation.js.map +0 -1
- package/dist/src/workspace-grants.js.map +0 -1
- package/docs/ACCESS_CONTROL.md +0 -51
- package/docs/CLIENTS.md +0 -22
- package/docs/CONNECT_CHATGPT.md +0 -148
- package/docs/INSTALL.md +0 -62
- package/docs/INSTANCES.md +0 -83
- package/docs/OAUTH.md +0 -116
- package/docs/PLATFORMS.md +0 -29
- package/docs/README.md +0 -16
- package/docs/REMOTE_SETUP.md +0 -280
- package/docs/SECURITY.md +0 -15
- package/docs/assets/starmux-app-en.png +0 -0
- package/docs/assets/starmux-architecture.svg +0 -315
- package/src/dc-workspace-http.mjs +0 -3
- package/test/fixtures/p1-fixture.txt +0 -2
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-upstream-router.js","sourceRoot":"","sources":["../../src/mcp-upstream-router.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RouteDefinition,RouteInfo,Tool,ToolArguments,ToolInvocation,UpstreamRouter } from \"./contracts.js\";\n// MCP router: route upstream tool calls without implementing their functionality.\n// Registered upstream servers own their tools; the DC route retains native names.\n// Additional upstream tools are namespaced \"<route>__<nativeTool>\".\nexport class MCPRouteError extends Error {\n constructor(public readonly code: string){super(code);}\n}\nfunction invalid(message: string): never{throw new MCPRouteError(message);}\nfunction validRoute(route: unknown){\n return typeof route===\"string\"&&/^[a-z][a-z0-9_-]{0,39}$/.test(route);\n}\nexport function createMCPUpstreamRouter({routes,defaultRoute=\"desktop\"}: {routes: RouteDefinition[]; defaultRoute?: string}): UpstreamRouter{\n if(!Array.isArray(routes)||routes.length===0)invalid(\"ROUTES_REQUIRED\");\n const mapping=new Map<string,{route:string;nativeName:string;upstream: RouteDefinition[\"upstream\"];authorize: RouteDefinition[\"authorize\"]}>(),seenRoutes=new Set<string>(),catalog:Tool[]=[],routeInfos:RouteInfo[]=[];\n for(const {id,upstream,exposeNativeNames=false,authorize=null} of routes){\n if(!validRoute(id)||seenRoutes.has(id))invalid(\"INVALID_OR_DUPLICATE_ROUTE\");\n seenRoutes.add(id);\n if(!upstream||!Array.isArray(upstream.upstreamCatalog)||\n typeof upstream.forwardWorkspaceInvocation!==\"function\")invalid(\"INVALID_UPSTREAM\");\n const names=new Set();\n for(const tool of upstream.upstreamCatalog){\n if(typeof tool?.name!==\"string\"||!tool.name||names.has(tool.name)||\n !tool.inputSchema||typeof tool.inputSchema!==\"object\")\n invalid(\"INVALID_UPSTREAM_CATALOG\");\n names.add(tool.name);\n const publicName=exposeNativeNames?tool.name:id+\"__\"+tool.name;\n if(mapping.has(publicName)||publicName===\"health_check\"||\n publicName.startsWith(\"gateway_git_\"))invalid(\"ROUTED_TOOL_COLLISION\");\n mapping.set(publicName,{route:id,nativeName:tool.name,upstream,authorize});\n catalog.push({...structuredClone(tool),name:publicName});\n }\n routeInfos.push(Object.freeze({id,toolCount:names.size,nativeNames:exposeNativeNames}));\n }\n if(!seenRoutes.has(defaultRoute))invalid(\"DEFAULT_ROUTE_MISSING\");\n const resourceSource=routes.find(x=>x.id===defaultRoute)?.upstream;\n return Object.freeze({\n // Default native route's MCP App resources correspond to the unchanged\n // UI URIs advertised on its tools. Additional namespaced upstream\n // resource URIs require explicit collision/ownership contracts later.\n ...(typeof resourceSource?.listNativeResources===\"function\"&&\n typeof resourceSource?.readNativeResource===\"function\"?{\n async listResources(){return resourceSource.listNativeResources!();},\n async readResource(uri: string){return resourceSource.readNativeResource!(uri);},\n async listResourceTemplates(){\n return typeof resourceSource.listNativeResourceTemplates===\"function\"?\n resourceSource.listNativeResourceTemplates():[];\n }\n }:{}),\n upstreamCatalog:Object.freeze(catalog),\n routes:Object.freeze(routeInfos),\n routeFor(publicName: string){return mapping.get(publicName)?.route||null;},\n async authorizeExtension(publicName: string,args: ToolArguments){\n const target=mapping.get(publicName);\n if(!target||target.route===defaultRoute||\n typeof target.authorize!==\"function\")invalid(\"ROUTE_NOT_AUTHORIZED\");\n const checked=await target.authorize(target.nativeName,args||{});\n if(!checked||typeof checked!==\"object\"||Array.isArray(checked))\n invalid(\"ROUTE_AUTHORIZATION_FAILED\");\n return {name:publicName,arguments:checked};\n },\n async forwardWorkspaceInvocation(invocation: ToolInvocation){\n if(!invocation||typeof invocation.name!==\"string\"||\n !mapping.has(invocation.name))invalid(\"NO_SUCH_ROUTED_TOOL\");\n const target=mapping.get(invocation.name)!;\n return target.upstream.forwardWorkspaceInvocation({\n ...invocation,name:target.nativeName,arguments:invocation.arguments||{}\n });\n }\n });\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-keycloak.js","sourceRoot":"","sources":["../../src/oauth-keycloak.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,+EAA+E;AAC/E,MAAM,UAAU,aAAa,CAAC,QAAe,EAAC,QAAe,EAAC,WAAW,GAAC,KAAK;IAC7E,KAAI,MAAM,KAAK,IAAI,CAAC,QAAQ,EAAC,QAAQ,CAAC,EAAC,CAAC;QACtC,MAAM,CAAC,GAAC,IAAI,GAAG,CAAC,KAAK,CAAC,CAAC;QACvB,IAAG,CAAC,CAAC,QAAQ,IAAE,CAAC,CAAC,QAAQ,IAAE,CAAC,CAAC,IAAI,IAAE,CAAC,CAAC,MAAM,IAAE,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAG,QAAQ;YACvF,CAAC,WAAW,IAAE,CAAC,CAAC,QAAQ,KAAG,OAAO,IAAE,CAAC,WAAW,EAAC,WAAW,EAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;YAAC,MAAM,KAAK,CAAC,mCAAmC,CAAC,CAAC;IAClJ,CAAC;IACD,OAAO;QACL,KAAK,EAAC,SAAS,EAAC,OAAO,EAAC,IAAI,EAAC,mBAAmB,EAAC,KAAK,EAAC,oBAAoB,EAAC,KAAK;QACjF,WAAW,EAAC,WAAW,CAAA,CAAC,CAAA,MAAM,CAAA,CAAC,CAAA,UAAU,EAAC,mBAAmB,EAAC,GAAG,EAAC,kBAAkB,EAAC,IAAI,EAAC,oBAAoB,EAAC,CAAC;QAChH,YAAY,EAAC,CAAC,EAAC,IAAI,EAAC,gBAAgB,EAAC,QAAQ,EAAC,gBAAgB,EAAC,UAAU,EAAC,EAAC,wBAAwB,EAAC,MAAM;oBACxG,2BAA2B,EAAC,MAAM,EAAC,qBAAqB,EAAC,sCAAsC,EAAC;gBAChG,eAAe,EAAC,CAAC,EAAC,IAAI,EAAC,SAAS,EAAC,QAAQ,EAAC,gBAAgB,EAAC,cAAc,EAAC,iBAAiB;wBACzF,MAAM,EAAC,EAAC,oBAAoB,EAAC,MAAM,EAAC,EAAC,EAAC,EAAC,IAAI,EAAC,kBAAkB,EAAC,QAAQ,EAAC,gBAAgB,EAAC,cAAc,EAAC,sBAAsB;wBAC9H,MAAM,EAAC,EAAC,0BAA0B,EAAC,kBAAkB,EAAC,oBAAoB,EAAC,MAAM,EAAC,gBAAgB,EAAC,OAAO,EAAC,EAAC,CAAC,EAAC,CAAC;QACnH,OAAO,EAAC,CAAC,EAAC,QAAQ,EAAC,kBAAkB,EAAC,IAAI,EAAC,kBAAkB,EAAC,OAAO,EAAC,IAAI,EAAC,QAAQ,EAAC,gBAAgB;gBAClG,UAAU,EAAC,IAAI,EAAC,UAAU,EAAC,EAAC,YAAY,EAAC,QAAQ,EAAC,EAAC;YACnD,EAAC,QAAQ,EAAC,iBAAiB,EAAC,IAAI,EAAC,4BAA4B,EAAC,OAAO,EAAC,IAAI,EAAC,QAAQ,EAAC,gBAAgB;gBAClG,YAAY,EAAC,KAAK,EAAC,uBAAuB,EAAC,eAAe,EAAC,mBAAmB,EAAC,IAAI,EAAC,yBAAyB,EAAC,KAAK,EAAC,mBAAmB,EAAC,KAAK;gBAC7I,sBAAsB,EAAC,KAAK,EAAC,eAAe,EAAC,IAAI,EAAC,YAAY,EAAC,CAAC,QAAQ,CAAC,EAAC,UAAU,EAAC,EAAE;gBACvF,UAAU,EAAC,EAAC,4BAA4B,EAAC,MAAM,EAAC,EAAC,oBAAoB,EAAC,CAAC,gBAAgB,CAAC,EAAC,mBAAmB,EAAC,EAAE,EAAC,CAAC;KACtH,CAAC;AACJ,CAAC","sourcesContent":["// A reference realm generator, not an embedded authorization server.\n// No users, passwords, client secrets or wildcard callback URLs are generated.\nexport function keycloakRealm(resource:string,callback:string,development=false){\n for(const value of [resource,callback]){\n const u=new URL(value);\n if(u.username||u.password||u.hash||u.search||value.includes('*')||!(u.protocol==='https:'||\n (development&&u.protocol==='http:'&&['127.0.0.1','localhost','[::1]'].includes(u.hostname))))throw Error('KEYCLOAK_HTTPS_EXACT_URL_REQUIRED');\n }\n return {\n realm:'gateway',enabled:true,registrationAllowed:false,resetPasswordAllowed:false,\n sslRequired:development?'none':'external',accessTokenLifespan:300,revokeRefreshToken:true,refreshTokenMaxReuse:0,\n clientScopes:[{name:'gateway:access',protocol:'openid-connect',attributes:{'include.in.token.scope':'true',\n 'display.on.consent.screen':'true','consent.screen.text':'Use the Gateway owner-approved tools'},\n protocolMappers:[{name:'Subject',protocol:'openid-connect',protocolMapper:'oidc-sub-mapper',\n config:{'access.token.claim':'true'}},{name:'gateway audience',protocol:'openid-connect',protocolMapper:'oidc-audience-mapper',\n config:{'included.client.audience':'gateway-resource','access.token.claim':'true','id.token.claim':'false'}}]}],\n clients:[{clientId:'gateway-resource',name:'Gateway resource',enabled:true,protocol:'openid-connect',\n bearerOnly:true,attributes:{resource_url:resource}},\n {clientId:'gateway-chatgpt',name:'ChatGPT Gateway connection',enabled:true,protocol:'openid-connect',\n publicClient:false,clientAuthenticatorType:'client-secret',standardFlowEnabled:true,directAccessGrantsEnabled:false,implicitFlowEnabled:false,\n serviceAccountsEnabled:false,consentRequired:true,redirectUris:[callback],webOrigins:[],\n attributes:{'pkce.code.challenge.method':'S256'},optionalClientScopes:['gateway:access'],defaultClientScopes:[]}]\n };\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"oauth-resource.js","sourceRoot":"","sources":["../../src/oauth-resource.ts"],"names":[],"mappings":"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","sourcesContent":["// OAuth resource-server adapter. The authorization server owns login, consent,\n// authorization codes, refresh tokens and client registration.\nimport {z} from 'zod';\nimport {createRemoteJWKSet,jwtVerify,type JWTVerifyGetKey} from 'jose';\nimport {createHash} from 'node:crypto';\n\nconst url=z.string().url().max(2048);\nexport const oauthConfigSchema=z.object({\n issuer:url,resource:url,jwksUri:url,authorizationEndpoint:url,tokenEndpoint:url,\n // Exact alternate identifiers for this same resource, explicitly approved by the owner.\n resourceAliases:z.array(url).max(8).optional(),\n registrationEndpoint:url.optional(),clientRegistration:z.enum(['provided','cimd','dcr']),\n clientId:z.string().min(1).max(2048),tokenEndpointAuthMethod:z.enum(['none','client_secret_basic','client_secret_post','private_key_jwt']),\n allowedSubjects:z.array(z.string().min(1).max(256)).min(1).max(32),\n scope:z.string().regex(/^[A-Za-z0-9:_-]{1,80}$/).default('gateway:access'),\n allowLoopbackHttp:z.boolean().default(false)\n}).strict();\nexport type OAuthConfig=z.infer<typeof oauthConfigSchema>;\nexport const oauthConnectionSchema=z.object({\n id:z.string().regex(/^[a-f0-9]{64}$/),subjectHash:z.string().regex(/^[a-f0-9]{64}$/),\n clientId:z.string().min(1).max(2048),createdAt:z.string().datetime(),lastUsedAt:z.string().datetime(),\n revokedAt:z.string().datetime().nullable(),permission:z.literal('owner-default')\n}).strict();\nexport type OAuthConnection=z.infer<typeof oauthConnectionSchema>;\nexport class OAuthError extends Error {\n constructor(readonly status:401|403|503,readonly reason:string){super(reason);}\n}\nfunction checkedUrl(value:string,allowHttp:boolean){\n if(/[\\u0000-\\u0020\\u007f\\\\]/.test(value))throw Error('OAUTH_URL_INVALID');\n const parsed=new URL(value);\n if(parsed.username||parsed.password||parsed.hash||parsed.search||\n !(parsed.protocol==='https:'||(allowHttp&&parsed.protocol==='http:'&&['localhost','127.0.0.1','[::1]'].includes(parsed.hostname))))\n throw Error('OAUTH_HTTPS_URL_REQUIRED');\n return parsed;\n}\nexport function validateOAuthConfig(value:unknown):OAuthConfig{\n const c=oauthConfigSchema.parse(value);\n const issuer=checkedUrl(c.issuer,c.allowLoopbackHttp);\n checkedUrl(c.resource,c.allowLoopbackHttp);\n for(const alias of c.resourceAliases??[])checkedUrl(alias,c.allowLoopbackHttp);\n for(const value of [c.jwksUri,c.authorizationEndpoint,c.tokenEndpoint,...(c.registrationEndpoint?[c.registrationEndpoint]:[])]){\n if(checkedUrl(value,c.allowLoopbackHttp).origin!==issuer.origin)throw Error('OAUTH_ENDPOINT_ORIGIN_MISMATCH');\n }\n if(c.clientRegistration==='dcr'&&!c.registrationEndpoint)throw Error('OAUTH_DCR_ENDPOINT_REQUIRED');\n return c;\n}\nconst discoverySchema=z.object({\n issuer:url,jwks_uri:url,authorization_endpoint:url,token_endpoint:url,\n registration_endpoint:url.optional(),client_id_metadata_document_supported:z.boolean().optional(),\n code_challenge_methods_supported:z.array(z.string()),response_types_supported:z.array(z.string()),\n token_endpoint_auth_methods_supported:z.array(z.string()).optional(),scopes_supported:z.array(z.string()).optional()\n});\nexport async function discoverOAuth(input:{issuer:string;resource:string;clientId:string;allowedSubjects:string[];\n clientRegistration?:'provided'|'cimd'|'dcr';tokenEndpointAuthMethod?:OAuthConfig['tokenEndpointAuthMethod'];allowLoopbackHttp?:boolean}){\n const issuer=checkedUrl(input.issuer,input.allowLoopbackHttp??false);\n checkedUrl(input.resource,input.allowLoopbackHttp??false);\n const base=issuer.pathname.replace(/\\/$/,'');\n const candidates=[issuer.origin+'/.well-known/oauth-authorization-server'+base,\n issuer.origin+base+'/.well-known/openid-configuration'];\n let metadata:z.infer<typeof discoverySchema>|undefined;\n for(const address of candidates){\n try{\n const response=await fetch(address,{redirect:'error',signal:AbortSignal.timeout(5000)});\n if(!response.ok||!response.body)continue;\n const reader=response.body.getReader();let body='';const decoder=new TextDecoder();let length=0;\n try{for(;;){const chunk=await reader.read();if(chunk.done)break;length+=chunk.value.byteLength;\n if(length>65536)throw Error('OAUTH_METADATA_TOO_LARGE');body+=decoder.decode(chunk.value,{stream:true});}}\n finally{await reader.cancel();}\n body+=decoder.decode();metadata=discoverySchema.parse(JSON.parse(body) as unknown);break;\n }catch{/* Try the standard OIDC discovery location; never accept redirects. */}\n }\n if(!metadata)throw Error('OAUTH_DISCOVERY_FAILED');\n if(metadata.issuer!==input.issuer)throw Error('OAUTH_ISSUER_MISMATCH');\n if(!metadata.code_challenge_methods_supported.includes('S256')||!metadata.response_types_supported.includes('code'))throw Error('OAUTH_CODE_PKCE_S256_REQUIRED');\n const registration=input.clientRegistration??'provided';const method=input.tokenEndpointAuthMethod??'none';\n if(!metadata.token_endpoint_auth_methods_supported?.includes(method))throw Error('OAUTH_TOKEN_AUTH_METHOD_UNSUPPORTED');\n if(registration==='cimd'&&!metadata.client_id_metadata_document_supported)throw Error('OAUTH_CIMD_NOT_ADVERTISED');\n if(registration==='dcr'&&!metadata.registration_endpoint)throw Error('OAUTH_DCR_NOT_ADVERTISED');\n return validateOAuthConfig({issuer:input.issuer,resource:input.resource,jwksUri:metadata.jwks_uri,\n authorizationEndpoint:metadata.authorization_endpoint,tokenEndpoint:metadata.token_endpoint,\n ...(metadata.registration_endpoint?{registrationEndpoint:metadata.registration_endpoint}:{}),\n clientRegistration:registration,clientId:input.clientId,tokenEndpointAuthMethod:method,\n allowedSubjects:input.allowedSubjects,allowLoopbackHttp:input.allowLoopbackHttp??false,scope:'gateway:access'});\n}\nexport function metadataUrl(c:OAuthConfig){\n const resource=new URL(c.resource);\n return resource.origin+'/.well-known/oauth-protected-resource'+resource.pathname.replace(/\\/$/,'');\n}\nexport function resourceMetadata(c:OAuthConfig){\n return {resource:c.resource,authorization_servers:[c.issuer],scopes_supported:[c.scope],bearer_methods_supported:['header']};\n}\nexport function oauthChallenge(c:OAuthConfig,status:401|403=401){\n // URLs and scope are validated and encoded as quoted-string contents.\n const quote=(s:string)=>s.replace(/\\\\/g,'\\\\\\\\').replace(/\"/g,'\\\\\"');\n return `Bearer resource_metadata=\"${quote(metadataUrl(c))}\", scope=\"${quote(c.scope)}\", error=\"${status===403?'insufficient_scope':'invalid_token'}\"`;\n}\nexport function createOAuthVerifier(c:OAuthConfig,key?:JWTVerifyGetKey){\n const keyset=key??createRemoteJWKSet(new URL(c.jwksUri),{timeoutDuration:4000,cooldownDuration:1000,cacheMaxAge:300000});\n return async(header:string|undefined)=>{\n if(!header||header.length>16384||!/^Bearer [^\\s]+$/i.test(header))throw new OAuthError(401,'OAUTH_TOKEN_REQUIRED');\n let payload;\n try{({payload}=await jwtVerify(header.slice(7),keyset,{issuer:c.issuer,audience:[c.resource,...(c.resourceAliases??[])],algorithms:['RS256','ES256','PS256'],\n requiredClaims:['sub','exp','iat','sid','azp'],clockTolerance:0}));}\n catch(error){\n const code=error&&typeof error==='object'&&'code' in error?error.code:'';\n if(code==='ERR_JWKS_TIMEOUT'||error instanceof TypeError)throw new OAuthError(503,'OAUTH_KEYS_UNAVAILABLE');\n throw new OAuthError(401,'OAUTH_TOKEN_INVALID');\n }\n if(typeof payload.sub!=='string'||!payload.sub||payload.sub.length>256||\n typeof payload.sid!=='string'||!payload.sid||payload.sid.length>512||payload.azp!==c.clientId||\n typeof payload.iat!=='number'||!Number.isSafeInteger(payload.iat)||payload.iat>Math.floor(Date.now()/1000)||\n typeof payload.exp!=='number'||!Number.isSafeInteger(payload.exp)||payload.exp<=payload.iat)\n throw new OAuthError(401,'OAUTH_TOKEN_INVALID');\n if(!c.allowedSubjects.includes(payload.sub))throw new OAuthError(403,'OAUTH_SUBJECT_NOT_ALLOWED');\n const scopes=typeof payload.scope==='string'?payload.scope.split(/\\s+/):[];\n if(!scopes.includes(c.scope))throw new OAuthError(403,'OAUTH_SCOPE_REQUIRED');\n const hash=(parts:string[])=>createHash('sha256').update(JSON.stringify(parts)).digest('hex');\n return {id:hash([c.issuer,payload.sub,c.clientId,payload.sid]),subjectHash:hash([c.issuer,payload.sub]),\n clientId:c.clientId,scopes};\n };\n}\n"]}
|
package/dist/src/operator-cli.js
DELETED
|
@@ -1,559 +0,0 @@
|
|
|
1
|
-
import { ownedByUser, supportedHost, windows, childEnvKeys } from "./platform.js";
|
|
2
|
-
import { privateAgentSchema } from "./config-schemas.js";
|
|
3
|
-
import { legacyCliEntry as cliEntry, packageRoot } from "./runtime-paths.js";
|
|
4
|
-
import { runtimeIdentity, formatStartup } from "./runtime-identity.js";
|
|
5
|
-
import { GatewayError, errorCode, errorMessage, errorStderr, isInteger, isSafeInteger, parseJSON, record } from "./validation.js";
|
|
6
|
-
// Operator-facing foreground CLI and explicit, per-user launchd lifecycle.
|
|
7
|
-
// Adopt existing private service without overwriting its checked plist.
|
|
8
|
-
import { execFile as execFileCallback, spawn } from "node:child_process";
|
|
9
|
-
import { access, lstat, readFile } from "node:fs/promises";
|
|
10
|
-
import net from "node:net";
|
|
11
|
-
import { homedir } from "node:os";
|
|
12
|
-
import path from "node:path";
|
|
13
|
-
import { promisify } from "node:util";
|
|
14
|
-
import { acquireControl, connectOwner, globalStop } from "./global-core-control.js";
|
|
15
|
-
import { defaultSetupPath, loadSetupConfig, setupRuntimeEnv } from "./release1-onboarding.js";
|
|
16
|
-
import { SERVICE_LABEL, launchAgentPaths, serviceCommand } from "./release1-service.js";
|
|
17
|
-
const execFile = promisify(execFileCallback);
|
|
18
|
-
const PRIVATE_LABEL = "ai.home.mac-mcp-project-workspace";
|
|
19
|
-
function failure(x) { const e = new GatewayError(x); throw e; }
|
|
20
|
-
;
|
|
21
|
-
const goodPort = (n) => isSafeInteger(n) && n >= 1024 && n <= 65535;
|
|
22
|
-
export function classifyServiceRuntime({ registered = false, portBusy = false, healthy = false, ownedPid = false } = {}) {
|
|
23
|
-
if (registered)
|
|
24
|
-
return healthy ? "service-healthy" : "service-unhealthy";
|
|
25
|
-
if (!portBusy)
|
|
26
|
-
return "stopped";
|
|
27
|
-
if (healthy && ownedPid)
|
|
28
|
-
return "foreground";
|
|
29
|
-
return "unknown-listener";
|
|
30
|
-
}
|
|
31
|
-
export function serviceActionDecision(action, { registered = false, portBusy = false } = {}) {
|
|
32
|
-
if (action === "start") {
|
|
33
|
-
if (registered)
|
|
34
|
-
return "ALREADY_RUNNING";
|
|
35
|
-
return portBusy ? "PORT_IN_USE" : "START";
|
|
36
|
-
}
|
|
37
|
-
if (action === "restart") {
|
|
38
|
-
if (!registered && portBusy)
|
|
39
|
-
return "FOREGROUND_IN_USE";
|
|
40
|
-
return registered ? "RESTART" : "START";
|
|
41
|
-
}
|
|
42
|
-
if (action === "stop")
|
|
43
|
-
return registered ? "STOP" : "ALREADY_STOPPED";
|
|
44
|
-
throw Error("INVALID_SERVICE_ACTION");
|
|
45
|
-
}
|
|
46
|
-
const privatePlist = (home) => path.join(home, "Library", "LaunchAgents", PRIVATE_LABEL + ".plist");
|
|
47
|
-
async function owned(p, uid, required = false) {
|
|
48
|
-
let st;
|
|
49
|
-
try {
|
|
50
|
-
st = await lstat(p);
|
|
51
|
-
}
|
|
52
|
-
catch (e) {
|
|
53
|
-
if (errorCode(e) === "ENOENT" && !required)
|
|
54
|
-
return false;
|
|
55
|
-
throw e;
|
|
56
|
-
}
|
|
57
|
-
if (st.isSymbolicLink() || !st.isFile() || st.nlink !== 1 || !ownedByUser(p, st) || (process.platform !== "win32" && (st.mode & 0o022)))
|
|
58
|
-
failure("UNTRUSTED_OWNER_FILE");
|
|
59
|
-
return true;
|
|
60
|
-
}
|
|
61
|
-
async function parsePlist(p) {
|
|
62
|
-
const { stdout } = await execFile("/usr/bin/plutil", ["-convert", "json", "-o", "-", p], { timeout: 5000, maxBuffer: 20000 });
|
|
63
|
-
let a;
|
|
64
|
-
try {
|
|
65
|
-
a = parseJSON(stdout);
|
|
66
|
-
}
|
|
67
|
-
catch {
|
|
68
|
-
failure("PLIST_INVALID");
|
|
69
|
-
}
|
|
70
|
-
return a;
|
|
71
|
-
}
|
|
72
|
-
function validatePrivate(value, home) {
|
|
73
|
-
const parsed = privateAgentSchema.safeParse(value);
|
|
74
|
-
if (!parsed.success)
|
|
75
|
-
failure("PRIVATE_RUNTIME_UNRECOGNIZED");
|
|
76
|
-
const a = parsed.data;
|
|
77
|
-
const files = a?.ProgramArguments;
|
|
78
|
-
const env = a?.EnvironmentVariables;
|
|
79
|
-
if (a?.Label !== PRIVATE_LABEL || !Array.isArray(files) || files.length !== 2 ||
|
|
80
|
-
typeof files[0] !== "string" || typeof files[1] !== "string" ||
|
|
81
|
-
!files[1].startsWith(path.join(home, "Library", "Application Support", "Mac-MCP-Gateway", "releases") + path.sep) ||
|
|
82
|
-
path.basename(files[1]) !== "dc-workspace-http.mjs" ||
|
|
83
|
-
a.WorkingDirectory !== path.dirname(path.dirname(files[1])) ||
|
|
84
|
-
!env || env.MAC_MCP_PROJECT_PORT !== "8793")
|
|
85
|
-
failure("PRIVATE_RUNTIME_UNRECOGNIZED");
|
|
86
|
-
return a;
|
|
87
|
-
}
|
|
88
|
-
async function locate(home, uid, profile = "auto") {
|
|
89
|
-
if (!["live", "setup", "auto"].includes(profile))
|
|
90
|
-
failure("INVALID_PROFILE");
|
|
91
|
-
if (process.platform !== "darwin") {
|
|
92
|
-
if (profile === "live")
|
|
93
|
-
failure("LEGACY_PROFILE_MACOS_ONLY");
|
|
94
|
-
return { kind: "setup", label: SERVICE_LABEL, plist: "", installed: false, files: [] };
|
|
95
|
-
}
|
|
96
|
-
const privateFile = privatePlist(home);
|
|
97
|
-
const hasSetup = profile === "auto" && await owned(defaultSetupPath(home), uid);
|
|
98
|
-
if (profile === "live" || (profile === "auto" && !hasSetup && await owned(privateFile, uid))) {
|
|
99
|
-
await owned(privateFile, uid, true);
|
|
100
|
-
const a = validatePrivate(await parsePlist(privateFile), home);
|
|
101
|
-
return { kind: "live", label: PRIVATE_LABEL, plist: privateFile, agent: a, installed: true,
|
|
102
|
-
files: [a.StandardOutPath, a.StandardErrorPath].filter((value) => typeof value === "string" && value.length > 0) };
|
|
103
|
-
}
|
|
104
|
-
const pl = launchAgentPaths(home);
|
|
105
|
-
return { kind: "setup", label: SERVICE_LABEL, plist: pl.plist,
|
|
106
|
-
installed: await owned(pl.plist, uid),
|
|
107
|
-
files: [path.join(pl.logs, "out.log"), path.join(pl.logs, "err.log")] };
|
|
108
|
-
}
|
|
109
|
-
async function registered(label, uid) {
|
|
110
|
-
if (process.platform !== "darwin")
|
|
111
|
-
return false;
|
|
112
|
-
try {
|
|
113
|
-
await execFile("/bin/launchctl", ["print", "gui/" + uid + "/" + label], { timeout: 5000, maxBuffer: 10000 });
|
|
114
|
-
return true;
|
|
115
|
-
}
|
|
116
|
-
catch {
|
|
117
|
-
return false;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
async function launch(command, uid, plist) {
|
|
121
|
-
try {
|
|
122
|
-
await execFile("/bin/launchctl", [command, "gui/" + uid, plist], { timeout: 12000, maxBuffer: 20000 });
|
|
123
|
-
}
|
|
124
|
-
catch (e) {
|
|
125
|
-
failure("LAUNCHCTL_" + command.toUpperCase() + "_FAILED " +
|
|
126
|
-
String(errorStderr(e) || errorMessage(e)).slice(0, 120));
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
async function available(port) {
|
|
130
|
-
return new Promise(resolve => {
|
|
131
|
-
const server = net.createServer();
|
|
132
|
-
server.once("error", () => resolve(false));
|
|
133
|
-
server.listen(port, "127.0.0.1", () => server.close(() => resolve(true)));
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
async function disabledFlag(label, uid) {
|
|
137
|
-
if (process.platform !== "darwin")
|
|
138
|
-
return true;
|
|
139
|
-
try {
|
|
140
|
-
const { stdout } = await execFile("/bin/launchctl", ["print-disabled", "gui/" + uid], { timeout: 5000, maxBuffer: 120000 });
|
|
141
|
-
const line = stdout.split("\n").find(s => s.includes('"' + label + '" =>'));
|
|
142
|
-
if (!line)
|
|
143
|
-
return null;
|
|
144
|
-
return line.includes("=> disabled");
|
|
145
|
-
}
|
|
146
|
-
catch {
|
|
147
|
-
return null;
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
async function setAutostart(label, uid, enabled) {
|
|
151
|
-
try {
|
|
152
|
-
await execFile("/bin/launchctl", [enabled ? "enable" : "disable",
|
|
153
|
-
"gui/" + uid + "/" + label], { timeout: 7000, maxBuffer: 15000 });
|
|
154
|
-
}
|
|
155
|
-
catch (e) {
|
|
156
|
-
failure("LAUNCHCTL_AUTOSTART_CHANGE_FAILED " +
|
|
157
|
-
String(errorStderr(e) || errorMessage(e)).slice(0, 90));
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
async function listenerOwner(port, expectedEntry) {
|
|
161
|
-
if (process.platform !== "darwin")
|
|
162
|
-
return null;
|
|
163
|
-
try {
|
|
164
|
-
const { stdout } = await execFile("/usr/sbin/lsof", [
|
|
165
|
-
"-nP", "-t", "-iTCP:" + port, "-sTCP:LISTEN"
|
|
166
|
-
], { timeout: 4000 });
|
|
167
|
-
const pid = Number(stdout.trim().split("\n")[0]);
|
|
168
|
-
if (!isSafeInteger(pid) || pid < 2)
|
|
169
|
-
return null;
|
|
170
|
-
const info = await execFile("/bin/ps", ["-p", String(pid), "-o", "command="], { timeout: 4000 });
|
|
171
|
-
return { pid, matchingEntry: info.stdout.trim().includes(expectedEntry) };
|
|
172
|
-
}
|
|
173
|
-
catch {
|
|
174
|
-
return null;
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
async function waitForHealthy(port, attempts = 24) {
|
|
178
|
-
for (let i = 0; i < attempts; i++) {
|
|
179
|
-
try {
|
|
180
|
-
const r = await fetch("http://127.0.0.1:" + port + "/healthz", {
|
|
181
|
-
signal: AbortSignal.timeout(700)
|
|
182
|
-
});
|
|
183
|
-
if (r.ok && record(await r.json()).status === "ok")
|
|
184
|
-
return true;
|
|
185
|
-
}
|
|
186
|
-
catch { }
|
|
187
|
-
await new Promise(resolve => setTimeout(resolve, 250));
|
|
188
|
-
}
|
|
189
|
-
return false;
|
|
190
|
-
}
|
|
191
|
-
async function waitUntilFree(port, attempts = 24) {
|
|
192
|
-
for (let i = 0; i < attempts; i++) {
|
|
193
|
-
if (await available(port))
|
|
194
|
-
return true;
|
|
195
|
-
await new Promise(resolve => setTimeout(resolve, 250));
|
|
196
|
-
}
|
|
197
|
-
return false;
|
|
198
|
-
}
|
|
199
|
-
async function envFor(info, home) {
|
|
200
|
-
return info.kind === "live" ? { ...info.agent.EnvironmentVariables } :
|
|
201
|
-
setupRuntimeEnv(await loadSetupConfig(defaultSetupPath(home)));
|
|
202
|
-
}
|
|
203
|
-
async function currentStatus(info, uid, home, portOverride) {
|
|
204
|
-
const active = await registered(info.label, uid);
|
|
205
|
-
// First-run setup is a user-owned 0600 profile, NOT an installed
|
|
206
|
-
// launchd Service. Inspect it directly to discover the Core port.
|
|
207
|
-
let env = info.kind === "live" ? info.agent.EnvironmentVariables : null;
|
|
208
|
-
if (info.kind === "setup") {
|
|
209
|
-
try {
|
|
210
|
-
env = await envFor(info, home);
|
|
211
|
-
}
|
|
212
|
-
catch (e) {
|
|
213
|
-
if (!["ENOENT", "SETUP_CONFIG_MISSING"].includes(errorCode(e) || ""))
|
|
214
|
-
throw e;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
const port = portOverride ?? (env ? Number(env.MAC_MCP_PROJECT_PORT) : null);
|
|
218
|
-
const portBusy = goodPort(port) ? !(await available(port)) : false;
|
|
219
|
-
let health = portBusy ? "unreachable" : "not-running";
|
|
220
|
-
let workspaceMode = null;
|
|
221
|
-
let writeScope = null;
|
|
222
|
-
let accessMode = null;
|
|
223
|
-
if (portBusy && port !== null) {
|
|
224
|
-
try {
|
|
225
|
-
const r = await fetch("http://127.0.0.1:" + port + "/healthz", {
|
|
226
|
-
signal: AbortSignal.timeout(2000)
|
|
227
|
-
});
|
|
228
|
-
const data = record(await r.json());
|
|
229
|
-
if (data.accessMode === "ingress" || data.accessMode === "api-key" || data.accessMode === "oauth" || data.accessMode === "unavailable")
|
|
230
|
-
accessMode = data.accessMode;
|
|
231
|
-
if (r.ok && data.status === "ok" && typeof data.mode === "string" && ["read-only", "read-write"].includes(data.mode))
|
|
232
|
-
workspaceMode = data.mode;
|
|
233
|
-
if (r.ok && data.status === "ok" && typeof data.writeScope === "string" && ["home-only", "unrestricted"].includes(data.writeScope))
|
|
234
|
-
writeScope = data.writeScope;
|
|
235
|
-
health = r.ok && data.status === "ok" &&
|
|
236
|
-
data.service === "dc-project-workspace" ? "ok" : "unrecognized";
|
|
237
|
-
}
|
|
238
|
-
catch {
|
|
239
|
-
health = "unreachable";
|
|
240
|
-
}
|
|
241
|
-
}
|
|
242
|
-
const owner = portBusy && port !== null ? await listenerOwner(port, info.kind === "live" ? info.agent.ProgramArguments[1] : "dc-workspace-http.mjs") : null;
|
|
243
|
-
let trustedControl = false;
|
|
244
|
-
if (portBusy && goodPort(port)) {
|
|
245
|
-
try {
|
|
246
|
-
const lease = await connectOwner(port);
|
|
247
|
-
trustedControl = lease?.result.result === "RUNNING";
|
|
248
|
-
}
|
|
249
|
-
catch { /* Do not trust a malformed/unresponsive owner lease. */ }
|
|
250
|
-
}
|
|
251
|
-
const executionMode = classifyServiceRuntime({
|
|
252
|
-
registered: active, portBusy, healthy: health === "ok",
|
|
253
|
-
ownedPid: trustedControl || owner?.matchingEntry === true
|
|
254
|
-
});
|
|
255
|
-
const autostart = await disabledFlag(info.label, uid);
|
|
256
|
-
return { profile: info.kind, installed: info.installed, registered: active,
|
|
257
|
-
label: info.label, port, health, workspaceMode, writeScope, accessMode, executionMode, listenerPid: owner?.pid ?? null,
|
|
258
|
-
loginAutostart: autostart === null ? ((info.kind === "live" ? info.agent.RunAtLoad : undefined) === true ? "default-enabled" : "unknown") : autostart ? "disabled" : "enabled",
|
|
259
|
-
tcc: process.platform === "darwin" ? "Foreground Termius vs background launchd may have different macOS privacy access" : "Access follows the current OS account permissions" };
|
|
260
|
-
}
|
|
261
|
-
export async function executeServiceLifecycle(action, { registered: running, portBusy: busy, disable, enable, bootout, bootstrap, waitPortFree, waitHealthy, port }) {
|
|
262
|
-
const decision = serviceActionDecision(action, { registered: running, portBusy: busy });
|
|
263
|
-
if (decision === "PORT_IN_USE" || decision === "FOREGROUND_IN_USE")
|
|
264
|
-
failure("FOREGROUND_OR_OTHER_LISTENER_ACTIVE: port " + port +
|
|
265
|
-
" already in use; refusing to start competing service");
|
|
266
|
-
if (action === "stop") {
|
|
267
|
-
if (running)
|
|
268
|
-
await bootout();
|
|
269
|
-
await disable();
|
|
270
|
-
const freed = running ? await waitPortFree() : !busy;
|
|
271
|
-
return { result: decision === "STOP" ? "STOPPED" : "ALREADY_STOPPED",
|
|
272
|
-
loginAutostart: "disabled", portReleased: freed,
|
|
273
|
-
foregroundInstanceUntouched: !running && busy };
|
|
274
|
-
}
|
|
275
|
-
if (decision === "ALREADY_RUNNING")
|
|
276
|
-
return { result: decision };
|
|
277
|
-
if (decision === "RESTART") {
|
|
278
|
-
await bootout();
|
|
279
|
-
if (!await waitPortFree()) {
|
|
280
|
-
await disable();
|
|
281
|
-
failure("SERVICE_RESTART_PORT_NOT_RELEASED");
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
await enable();
|
|
285
|
-
try {
|
|
286
|
-
await bootstrap();
|
|
287
|
-
}
|
|
288
|
-
catch (e) {
|
|
289
|
-
await disable();
|
|
290
|
-
throw e;
|
|
291
|
-
}
|
|
292
|
-
if (!await waitHealthy()) {
|
|
293
|
-
try {
|
|
294
|
-
await bootout();
|
|
295
|
-
}
|
|
296
|
-
catch { /* job may already have exited */ }
|
|
297
|
-
await disable();
|
|
298
|
-
failure("SERVICE_START_HEALTH_TIMEOUT_ROLLED_BACK");
|
|
299
|
-
}
|
|
300
|
-
return { result: decision === "RESTART" ? "RESTARTED" : "STARTED",
|
|
301
|
-
loginAutostart: "enabled", health: "ok" };
|
|
302
|
-
}
|
|
303
|
-
async function manage(info, action, uid, home, entry) {
|
|
304
|
-
if (process.platform !== "darwin")
|
|
305
|
-
failure("BACKGROUND_SERVICE_UNSUPPORTED_USE_RUN");
|
|
306
|
-
if (action === "install") {
|
|
307
|
-
if (info.kind === "live")
|
|
308
|
-
failure("ALREADY_INSTALLED_NO_OVERWRITE");
|
|
309
|
-
const created = await serviceCommand("install", {
|
|
310
|
-
home, entry, configFile: defaultSetupPath(home)
|
|
311
|
-
});
|
|
312
|
-
// An installed LaunchAgent does not start again at login until the
|
|
313
|
-
// owner explicitly invokes start; install is not implicit consent.
|
|
314
|
-
await setAutostart(info.label, uid, false);
|
|
315
|
-
return { ...created, loginAutostart: "disabled" };
|
|
316
|
-
}
|
|
317
|
-
if (!info.installed)
|
|
318
|
-
failure("SERVICE_NOT_INSTALLED");
|
|
319
|
-
const running = await registered(info.label, uid);
|
|
320
|
-
const env = await envFor(info, home);
|
|
321
|
-
const port = Number(env.MAC_MCP_PROJECT_PORT);
|
|
322
|
-
if (!goodPort(port))
|
|
323
|
-
failure("INVALID_SERVICE_PORT");
|
|
324
|
-
const busy = !(await available(port));
|
|
325
|
-
const result = await executeServiceLifecycle(action, {
|
|
326
|
-
registered: running, portBusy: busy, port,
|
|
327
|
-
disable: () => setAutostart(info.label, uid, false),
|
|
328
|
-
enable: () => setAutostart(info.label, uid, true),
|
|
329
|
-
bootout: () => launch("bootout", uid, info.plist),
|
|
330
|
-
bootstrap: () => launch("bootstrap", uid, info.plist),
|
|
331
|
-
waitPortFree: () => waitUntilFree(port),
|
|
332
|
-
waitHealthy: () => waitForHealthy(port)
|
|
333
|
-
});
|
|
334
|
-
if (result.result === "ALREADY_RUNNING")
|
|
335
|
-
return { ...result, health: (await currentStatus(info, uid, home)).health };
|
|
336
|
-
return result;
|
|
337
|
-
}
|
|
338
|
-
async function logs(info, lines, uid) {
|
|
339
|
-
if (!isSafeInteger(lines) || lines < 1 || lines > 200)
|
|
340
|
-
failure("INVALID_LINES");
|
|
341
|
-
let output = "";
|
|
342
|
-
for (const p of info.files) {
|
|
343
|
-
if (typeof p !== "string" || !path.isAbsolute(p))
|
|
344
|
-
continue;
|
|
345
|
-
if (!await owned(p, uid))
|
|
346
|
-
continue;
|
|
347
|
-
const stdout = (await readFile(p, "utf8")).split("\n").slice(-lines - 1).join("\n");
|
|
348
|
-
// Only print to the owner's own terminal; no remote log upload.
|
|
349
|
-
output += "== " + p + " ==\n" + stdout;
|
|
350
|
-
}
|
|
351
|
-
return output || "No logs yet.\n";
|
|
352
|
-
}
|
|
353
|
-
async function runForeground(info, options, home, entry, uid) {
|
|
354
|
-
// App-managed foreground is still this exact CLI/Core, not a second
|
|
355
|
-
// execution engine. Bind the run to its *actual* immediate GUI parent.
|
|
356
|
-
const appParent = options.appParentPid;
|
|
357
|
-
if (appParent !== undefined && (!isSafeInteger(appParent) || appParent <= 1 ||
|
|
358
|
-
process.ppid !== appParent))
|
|
359
|
-
failure("APP_PARENT_IDENTITY_MISMATCH");
|
|
360
|
-
const env = await envFor(info, home);
|
|
361
|
-
const configuredPort = Number(env.MAC_MCP_PROJECT_PORT);
|
|
362
|
-
const port = options.port ?? configuredPort;
|
|
363
|
-
if (!goodPort(port))
|
|
364
|
-
failure("INVALID_PORT");
|
|
365
|
-
// Setup is the user's durable 0600 product configuration. An ad hoc
|
|
366
|
-
// --port must never make App status/topology disagree with the real Core.
|
|
367
|
-
if (info.kind === "setup" && port !== configuredPort)
|
|
368
|
-
failure("SETUP_PORT_OVERRIDE_DENIED_RECONFIGURE");
|
|
369
|
-
// The atomic owner lease arbitrates CLI vs App, not the local 8793
|
|
370
|
-
// listener. No second Gateway is ever spawned while the lease is held.
|
|
371
|
-
const control = await acquireControl(port, {
|
|
372
|
-
launcher: appParent === undefined ? "cli" : "app", root: options.controlRoot
|
|
373
|
-
});
|
|
374
|
-
try {
|
|
375
|
-
if (!await available(port))
|
|
376
|
-
failure("PORT_IN_USE: a Gateway or unknown local listener already uses this port");
|
|
377
|
-
env.MAC_MCP_PROJECT_PORT = String(port);
|
|
378
|
-
if (info.kind === "setup") {
|
|
379
|
-
env.MAC_MCP_INTERNAL_SETUP_OWNER_PID = String(process.pid);
|
|
380
|
-
env.MAC_MCP_INTERNAL_SETUP_RUN_ID = control.owner.runId;
|
|
381
|
-
env.MAC_MCP_INTERNAL_SETUP_TOKEN = control.owner.token;
|
|
382
|
-
}
|
|
383
|
-
// Legacy configuration supplies settings only, never a different executable.
|
|
384
|
-
const args = info.kind === "live" ? [process.execPath, path.join(packageRoot, "src", "dc-workspace-http.mjs")] : [
|
|
385
|
-
process.execPath, entry, "start-setup"
|
|
386
|
-
];
|
|
387
|
-
const cwd = packageRoot;
|
|
388
|
-
await owned(args[1], uid, true);
|
|
389
|
-
await access(cwd);
|
|
390
|
-
const identity = await runtimeIdentity();
|
|
391
|
-
const details = { ...identity, configSource: info.kind === "live" ? info.plist : defaultSetupPath(home), port };
|
|
392
|
-
const structured = options.json === true || appParent !== undefined;
|
|
393
|
-
process.stdout.write(structured ? JSON.stringify({ event: "GATEWAY_FOREGROUND_START",
|
|
394
|
-
...details, mode: info.kind, stop: "Ctrl+C", existingService: "untouched" }) + "\n" : formatStartup(details));
|
|
395
|
-
// Do not pass unrelated credentials from the operator's shell.
|
|
396
|
-
const inherited = {};
|
|
397
|
-
for (const key of childEnvKeys) {
|
|
398
|
-
if (typeof process.env[key] === "string")
|
|
399
|
-
inherited[key] = process.env[key];
|
|
400
|
-
}
|
|
401
|
-
if (process.env.MAC_MCP_ACCESS_FILE)
|
|
402
|
-
env.MAC_MCP_ACCESS_FILE = process.env.MAC_MCP_ACCESS_FILE;
|
|
403
|
-
const child = spawn(args[0], args.slice(1), {
|
|
404
|
-
cwd, env: { ...inherited, ...env }, stdio: windows ? ["inherit", "inherit", "inherit", "ipc"] : "inherit"
|
|
405
|
-
});
|
|
406
|
-
const stopChild = (signal) => {
|
|
407
|
-
if (child.exitCode !== null)
|
|
408
|
-
return;
|
|
409
|
-
if (windows && child.connected)
|
|
410
|
-
child.send({ type: "gateway-stop" }, () => { });
|
|
411
|
-
else
|
|
412
|
-
child.kill(signal);
|
|
413
|
-
};
|
|
414
|
-
const exited = new Promise(resolve => child.once("exit", () => resolve(true)));
|
|
415
|
-
control.onStop(async () => {
|
|
416
|
-
stopChild("SIGTERM");
|
|
417
|
-
const ended = await Promise.race([
|
|
418
|
-
exited, new Promise(resolve => { setTimeout(() => resolve(false), 8000).unref(); })
|
|
419
|
-
]);
|
|
420
|
-
if (!ended)
|
|
421
|
-
return "STOP_FAILED";
|
|
422
|
-
return await waitUntilFree(port, 14) ? "STOPPED" : "STOP_FAILED";
|
|
423
|
-
});
|
|
424
|
-
control.markRunning();
|
|
425
|
-
return await new Promise((resolve, reject) => {
|
|
426
|
-
const interrupt = () => { stopChild("SIGINT"); };
|
|
427
|
-
const terminate = () => { stopChild("SIGTERM"); };
|
|
428
|
-
process.on("SIGINT", interrupt);
|
|
429
|
-
process.on("SIGTERM", terminate);
|
|
430
|
-
// A force-quit/crash of the menu-bar App must not orphan the owned Core.
|
|
431
|
-
// Never monitor, signal or adopt any external listener. This check is
|
|
432
|
-
// activated only by --app-parent-pid; manual CLI Ctrl+C is unchanged.
|
|
433
|
-
const parentWatch = appParent === undefined ? null : setInterval(() => {
|
|
434
|
-
if (process.ppid !== appParent) {
|
|
435
|
-
terminate();
|
|
436
|
-
}
|
|
437
|
-
}, 400);
|
|
438
|
-
parentWatch?.unref();
|
|
439
|
-
const cleanup = () => {
|
|
440
|
-
process.off("SIGINT", interrupt);
|
|
441
|
-
process.off("SIGTERM", terminate);
|
|
442
|
-
if (parentWatch)
|
|
443
|
-
clearInterval(parentWatch);
|
|
444
|
-
};
|
|
445
|
-
child.once("error", e => { cleanup(); reject(e); });
|
|
446
|
-
child.once("exit", (code, signal) => {
|
|
447
|
-
cleanup();
|
|
448
|
-
process.stdout.write(structured ? JSON.stringify({ event: "GATEWAY_FOREGROUND_STOP", code, signal }) + "\n" :
|
|
449
|
-
`\n Core exited (${signal ?? code ?? "unknown"}).\n`);
|
|
450
|
-
control.markStopped();
|
|
451
|
-
resolve(code === null ? (signal === "SIGINT" ? 130 : 1) : code);
|
|
452
|
-
});
|
|
453
|
-
});
|
|
454
|
-
}
|
|
455
|
-
finally {
|
|
456
|
-
await control.release();
|
|
457
|
-
}
|
|
458
|
-
}
|
|
459
|
-
export function parseArgs(argv) {
|
|
460
|
-
const action = argv[0] || "help";
|
|
461
|
-
const options = {};
|
|
462
|
-
for (let i = 1; i < argv.length; i++) {
|
|
463
|
-
const option = argv[i];
|
|
464
|
-
if (option === "--json" && ["status", "run"].includes(action)) {
|
|
465
|
-
if (options.json)
|
|
466
|
-
failure("DUPLICATE_JSON_OPTION");
|
|
467
|
-
options.json = true;
|
|
468
|
-
continue;
|
|
469
|
-
}
|
|
470
|
-
if (option === "--all" && action === "privacy") {
|
|
471
|
-
options.all = true;
|
|
472
|
-
continue;
|
|
473
|
-
}
|
|
474
|
-
const v = argv[++i];
|
|
475
|
-
if (v === undefined)
|
|
476
|
-
failure("MISSING_OPTION_VALUE");
|
|
477
|
-
if (option === "--profile" && ["live", "setup", "auto"].includes(v)) {
|
|
478
|
-
options.profile = v;
|
|
479
|
-
}
|
|
480
|
-
else if (option === "--port" && ["run", "stop", "status"].includes(action) && goodPort(Number(v))) {
|
|
481
|
-
options.port = Number(v);
|
|
482
|
-
}
|
|
483
|
-
else if (option === "--app-parent-pid" && action === "run" &&
|
|
484
|
-
/^[1-9][0-9]*$/.test(v) && isSafeInteger(Number(v))) {
|
|
485
|
-
options.appParentPid = Number(v);
|
|
486
|
-
}
|
|
487
|
-
else if (option === "--target" && action === "privacy" && path.isAbsolute(v) &&
|
|
488
|
-
!v.includes("\0")) {
|
|
489
|
-
options.target = v;
|
|
490
|
-
}
|
|
491
|
-
else if (option === "--lines" && action === "logs" &&
|
|
492
|
-
isInteger(Number(v)) && Number(v) >= 1 && Number(v) <= 200) {
|
|
493
|
-
options.lines = Number(v);
|
|
494
|
-
}
|
|
495
|
-
else
|
|
496
|
-
failure("INVALID_OPTION");
|
|
497
|
-
}
|
|
498
|
-
return { action, options };
|
|
499
|
-
}
|
|
500
|
-
export async function operatorCommand(action, options = {}) {
|
|
501
|
-
supportedHost();
|
|
502
|
-
if (process.getuid?.() === 0)
|
|
503
|
-
failure("DO_NOT_RUN_AS_ROOT");
|
|
504
|
-
const home = options.home || homedir(), uid = process.getuid?.() ?? 0;
|
|
505
|
-
const info = await locate(home, uid, options.profile || "auto");
|
|
506
|
-
const entry = options.entry ?? cliEntry();
|
|
507
|
-
if (action === "status") {
|
|
508
|
-
const result = await currentStatus(info, uid, home, options.port);
|
|
509
|
-
const port = options.port ?? result.port ?? 8793;
|
|
510
|
-
let controller = null;
|
|
511
|
-
try {
|
|
512
|
-
controller = await connectOwner(port, { root: options.controlRoot });
|
|
513
|
-
}
|
|
514
|
-
catch { /* An unrecognized or stale local owner never grants stop rights. */ }
|
|
515
|
-
return { event: "GATEWAY_STATUS", ...result,
|
|
516
|
-
coreControl: controller?.result.result ?? "unavailable",
|
|
517
|
-
coreLauncher: controller?.owner.launcher ?? "unknown",
|
|
518
|
-
coreOwnerPid: controller?.owner.pid ?? null };
|
|
519
|
-
}
|
|
520
|
-
if (action === "logs")
|
|
521
|
-
return { event: "GATEWAY_LOGS",
|
|
522
|
-
output: await logs(info, options.lines ?? 60, uid) };
|
|
523
|
-
if (action === "privacy") {
|
|
524
|
-
if (process.platform !== "darwin")
|
|
525
|
-
failure("PRIVACY_DIAGNOSTICS_MACOS_ONLY");
|
|
526
|
-
const env = await envFor(info, home);
|
|
527
|
-
const { privacyReport } = await import("./privacy-diagnostics.js");
|
|
528
|
-
return privacyReport({ port: Number(env.MAC_MCP_PROJECT_PORT), home,
|
|
529
|
-
all: options.all === true, target: options.target ?? null });
|
|
530
|
-
}
|
|
531
|
-
if (action === "run")
|
|
532
|
-
return { event: "GATEWAY_RUN_EXIT",
|
|
533
|
-
code: await runForeground(info, options, home, entry, uid) };
|
|
534
|
-
if (action === "stop") {
|
|
535
|
-
const status = await currentStatus(info, uid, home, options.port);
|
|
536
|
-
const port = options.port ?? status.port ?? 8793;
|
|
537
|
-
const control = await globalStop(port, { root: options.controlRoot });
|
|
538
|
-
if (control.result === "NO_CONTROL_OWNER") {
|
|
539
|
-
if (!await available(port))
|
|
540
|
-
failure("CORE_STOP_REFUSED_UNKNOWN_LISTENER");
|
|
541
|
-
return { event: "GATEWAY_CORE", result: "ALREADY_STOPPED", port };
|
|
542
|
-
}
|
|
543
|
-
if (!await waitUntilFree(port, 12))
|
|
544
|
-
failure("CORE_STOP_UNVERIFIED_PORT_STILL_OCCUPIED");
|
|
545
|
-
return { event: "GATEWAY_CORE", ...control, port };
|
|
546
|
-
}
|
|
547
|
-
if (["install", "start", "restart"].includes(action))
|
|
548
|
-
failure("SERVICE_MODE_DEFERRED");
|
|
549
|
-
failure("INVALID_ACTION");
|
|
550
|
-
}
|
|
551
|
-
/** Validated legacy settings for the explicit instance migration workflow. */
|
|
552
|
-
export async function legacyProfileDetails(profile, home = homedir()) {
|
|
553
|
-
const uid = process.getuid?.() ?? 0;
|
|
554
|
-
const info = await locate(home, uid, profile);
|
|
555
|
-
const env = await envFor(info, home);
|
|
556
|
-
return { kind: info.kind, source: info.kind === 'setup' ? defaultSetupPath(home) : info.plist,
|
|
557
|
-
env, label: info.label, plist: info.plist, installed: info.installed, registered: await registered(info.label, uid) };
|
|
558
|
-
}
|
|
559
|
-
//# sourceMappingURL=operator-cli.js.map
|