@crewx/sdk 0.9.0-rc.5 → 0.9.0-rc.50
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/config/canonicalize-agent-options.d.ts +16 -0
- package/dist/config/global-settings.d.ts +19 -0
- package/dist/config/models.generated.d.ts +36 -0
- package/dist/config/models.remote.d.ts +4 -0
- package/dist/config/overdrive.d.ts +29 -0
- package/dist/config/pricing.d.ts +8 -8
- package/dist/config/pricing.generated.d.ts +2 -0
- package/dist/config/pricing.remote.d.ts +4 -0
- package/dist/config/pricing.types.d.ts +5 -0
- package/dist/config/timeout.config.d.ts +3 -0
- package/dist/config/wi-boards.d.ts +19 -0
- package/dist/desktop/command-runner.d.ts +4 -0
- package/dist/desktop/default-adapters.d.ts +4 -0
- package/dist/desktop/global-install.d.ts +19 -0
- package/dist/desktop/index.d.ts +2 -0
- package/dist/desktop/index.js +3 -0
- package/dist/desktop/install.d.ts +5 -0
- package/dist/desktop/lnk.d.ts +22 -0
- package/dist/desktop/manifest.d.ts +20 -0
- package/dist/desktop/types.d.ts +66 -0
- package/dist/desktop/version.d.ts +1 -0
- package/dist/desktop/windows-paths.d.ts +21 -0
- package/dist/desktop/wrapper.d.ts +18 -0
- package/dist/esm/desktop/index.js +3 -0
- package/dist/esm/index.js +149 -93
- package/dist/esm/plugins/index.js +118 -71
- package/dist/esm/publish/index.js +1 -0
- package/dist/esm/repository/index.js +122 -75
- package/dist/esm/testing/index.js +1 -1
- package/dist/events/types.d.ts +3 -0
- package/dist/facade/Crewx.d.ts +12 -0
- package/dist/index.browser.d.ts +4 -1
- package/dist/index.browser.js +6 -2
- package/dist/index.d.ts +26 -7
- package/dist/index.js +143 -87
- package/dist/internal/windows-spawn.d.ts +10 -0
- package/dist/migrations/0008_careful_black_bird.sql +17 -0
- package/dist/migrations/0009_hot_dark_phoenix.sql +1 -0
- package/dist/migrations/0010_analyze_stats.sql +6 -0
- package/dist/migrations/0011_far_black_tarantula.sql +1 -0
- package/dist/migrations/0012_blue_turbo.sql +23 -0
- package/dist/migrations/0013_hesitant_adam_destine.sql +15 -0
- package/dist/migrations/meta/0008_snapshot.json +1327 -0
- package/dist/migrations/meta/0009_snapshot.json +1335 -0
- package/dist/migrations/meta/0010_snapshot.json +1335 -0
- package/dist/migrations/meta/0011_snapshot.json +1342 -0
- package/dist/migrations/meta/0012_snapshot.json +1494 -0
- package/dist/migrations/meta/0013_snapshot.json +1592 -0
- package/dist/migrations/meta/_journal.json +42 -0
- package/dist/paths.d.ts +1 -0
- package/dist/plugin/types.d.ts +1 -0
- package/dist/plugins/index.js +118 -71
- package/dist/provider/acp/adapters/claude.d.ts +0 -4
- package/dist/provider/acp/connection.d.ts +4 -0
- package/dist/provider/acp/meta.d.ts +6 -0
- package/dist/provider/bridge.d.ts +13 -1
- package/dist/provider/classify-task-error.d.ts +2 -0
- package/dist/provider/cli/adapter.types.d.ts +1 -0
- package/dist/provider/cli/adapters/cli-knob.util.d.ts +2 -0
- package/dist/provider/cli/meta.d.ts +10 -2
- package/dist/provider/errors.d.ts +1 -0
- package/dist/provider/idle-watchdog.d.ts +19 -0
- package/dist/provider/models.d.ts +26 -0
- package/dist/provider/order.d.ts +1 -0
- package/dist/provider/parse-usage.d.ts +6 -0
- package/dist/provider/provider-selection.d.ts +8 -0
- package/dist/provider/redact-technical-message.d.ts +1 -0
- package/dist/provider/task-error.types.d.ts +16 -0
- package/dist/publish/auth-boundary.d.ts +22 -0
- package/dist/publish/auth-json.d.ts +11 -0
- package/dist/publish/constants.d.ts +6 -0
- package/dist/publish/index.d.ts +30 -0
- package/dist/publish/index.js +1 -0
- package/dist/publish/manifest.d.ts +17 -0
- package/dist/publish/marketplace-api.constants.d.ts +1 -0
- package/dist/publish/pack.d.ts +2 -0
- package/dist/publish/scan.d.ts +9 -0
- package/dist/publish/secrets.d.ts +6 -0
- package/dist/publish/upload.d.ts +18 -0
- package/dist/repository/agent-suggestion.repository.d.ts +34 -0
- package/dist/repository/index.d.ts +7 -1
- package/dist/repository/index.js +122 -75
- package/dist/repository/notification.repository.d.ts +58 -0
- package/dist/repository/task.repository.d.ts +79 -0
- package/dist/repository/thread.repository.d.ts +16 -2
- package/dist/repository/usage-report.repository.d.ts +27 -0
- package/dist/schema/agent-suggestions.d.ts +199 -0
- package/dist/schema/index.d.ts +3 -0
- package/dist/schema/notifications.d.ts +303 -0
- package/dist/schema/usage-reports.d.ts +252 -0
- package/dist/testing/index.d.ts +2 -0
- package/dist/testing/index.js +1 -1
- package/dist/types/index.d.ts +143 -3
- package/dist/utils/crewx-home.d.ts +1 -0
- package/dist/utils/id.d.ts +1 -1
- package/dist/wi/create.d.ts +48 -0
- package/dist/wi/select.d.ts +20 -0
- package/package.json +19 -3
- package/templates/agents/default.yaml +175 -117
- package/templates/documents/crewx-manual.md +138 -138
- package/templates/workflows/wi-default-flow.yaml +65 -0
- package/templates/workflows/wi-plan-flow.yaml +140 -0
package/README.md
CHANGED
|
@@ -128,7 +128,7 @@ const result = await crewx.query('assistant', 'Translate to Korean', {
|
|
|
128
128
|
});
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
-
> **Note**: `'@assistant'`
|
|
131
|
+
> **Note**: The `'@assistant'` form also works (CLI-compatible). The SDK recommends using the bare id.
|
|
132
132
|
|
|
133
133
|
**Returns**: [`QueryResult`](#queryresult)
|
|
134
134
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface AgentOptionsLike {
|
|
2
|
+
query?: unknown;
|
|
3
|
+
execute?: unknown;
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
}
|
|
6
|
+
export interface CanonicalizeAgentOptionsInput {
|
|
7
|
+
provider?: string;
|
|
8
|
+
model?: string;
|
|
9
|
+
options: unknown;
|
|
10
|
+
}
|
|
11
|
+
export interface CanonicalizeAgentOptionsResult {
|
|
12
|
+
options: unknown;
|
|
13
|
+
changed: boolean;
|
|
14
|
+
removed: string[];
|
|
15
|
+
}
|
|
16
|
+
export declare function canonicalizeAgentOptions(input: CanonicalizeAgentOptionsInput): CanonicalizeAgentOptionsResult;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface GlobalSettings {
|
|
2
|
+
cron?: {
|
|
3
|
+
auto_start?: boolean;
|
|
4
|
+
[key: string]: unknown;
|
|
5
|
+
};
|
|
6
|
+
[key: string]: unknown;
|
|
7
|
+
}
|
|
8
|
+
export type DeepPartial<T> = T extends object ? {
|
|
9
|
+
[K in keyof T]?: DeepPartial<T[K]>;
|
|
10
|
+
} : T;
|
|
11
|
+
export interface GlobalSettingsStore {
|
|
12
|
+
read(): GlobalSettings;
|
|
13
|
+
update(patch: DeepPartial<GlobalSettings>): GlobalSettings;
|
|
14
|
+
readonly path: string;
|
|
15
|
+
}
|
|
16
|
+
export interface CreateGlobalSettingsStoreOptions {
|
|
17
|
+
filePath?: string;
|
|
18
|
+
}
|
|
19
|
+
export declare function createGlobalSettingsStore(opts?: CreateGlobalSettingsStoreOptions): GlobalSettingsStore;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
export interface ModelCatalogEntry {
|
|
2
|
+
id: string;
|
|
3
|
+
name: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface ProviderModeEntry {
|
|
7
|
+
id: string;
|
|
8
|
+
name: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ProviderModelOverride {
|
|
12
|
+
effort?: string[];
|
|
13
|
+
defaultEffort?: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ProviderExecutionOptions {
|
|
16
|
+
mode: string;
|
|
17
|
+
effort: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ProviderDefaultProfile {
|
|
20
|
+
model: string;
|
|
21
|
+
query: ProviderExecutionOptions;
|
|
22
|
+
execute: ProviderExecutionOptions;
|
|
23
|
+
}
|
|
24
|
+
export interface ProviderDefaults {
|
|
25
|
+
version: number;
|
|
26
|
+
providers: Record<string, ProviderDefaultProfile>;
|
|
27
|
+
}
|
|
28
|
+
export interface ProviderCatalogEntry {
|
|
29
|
+
models: ModelCatalogEntry[];
|
|
30
|
+
modes: ProviderModeEntry[];
|
|
31
|
+
effort: string[];
|
|
32
|
+
modelOverrides: Record<string, ProviderModelOverride>;
|
|
33
|
+
}
|
|
34
|
+
export declare const PROVIDER_CATALOGS: Record<string, ProviderCatalogEntry>;
|
|
35
|
+
export declare const PROVIDER_DEFAULTS: ProviderDefaults;
|
|
36
|
+
export declare const PROVIDER_MODELS: Record<string, ModelCatalogEntry[]>;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
export interface OverdriveProfile {
|
|
2
|
+
provider?: string;
|
|
3
|
+
model?: string;
|
|
4
|
+
mode?: string;
|
|
5
|
+
effort?: string;
|
|
6
|
+
}
|
|
7
|
+
export type OverdriveSignalInput = boolean | {
|
|
8
|
+
mode?: 'count' | 'latch';
|
|
9
|
+
} | undefined;
|
|
10
|
+
export interface OverdriveSignal {
|
|
11
|
+
active: boolean;
|
|
12
|
+
mode?: 'count' | 'latch';
|
|
13
|
+
}
|
|
14
|
+
export declare function parseOverdriveProfile(raw: unknown): OverdriveProfile | undefined;
|
|
15
|
+
export declare function parseOverdriveSignal(signal: OverdriveSignalInput): OverdriveSignal;
|
|
16
|
+
export interface OverdriveResolution {
|
|
17
|
+
active: boolean;
|
|
18
|
+
provider?: string;
|
|
19
|
+
model?: string;
|
|
20
|
+
mode?: string;
|
|
21
|
+
effort?: string;
|
|
22
|
+
crossProvider: boolean;
|
|
23
|
+
}
|
|
24
|
+
export declare function resolveOverdrive(agentOptions: unknown, mode: 'query' | 'execute', baseProvider: string, signal: OverdriveSignal): OverdriveResolution;
|
|
25
|
+
export interface ModeOverrideResolution {
|
|
26
|
+
provider?: string;
|
|
27
|
+
model?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function resolveModeOverride(agentOptions: unknown, mode: 'query' | 'execute'): ModeOverrideResolution;
|
package/dist/config/pricing.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
export declare
|
|
1
|
+
import type { ModelPricing } from './pricing.types.js';
|
|
2
|
+
export type { ModelPricing } from './pricing.types.js';
|
|
3
|
+
export { MODEL_PRICING } from './pricing.generated.js';
|
|
4
|
+
export declare function setPricingOverride(models: Record<string, ModelPricing>): void;
|
|
5
|
+
export declare function clearPricingOverride(): void;
|
|
6
|
+
export declare function normalizeModel(model: string): string;
|
|
7
7
|
export declare function getPricing(model: string | null | undefined): ModelPricing;
|
|
8
|
-
export declare function calculateCost(inputTokens: number, outputTokens: number, model: string | null | undefined, cachedInputTokens?: number): number;
|
|
9
|
-
export declare function resolveCost(costUsd: number | undefined, inputTokens: number | undefined, outputTokens: number | undefined, cachedInputTokens: number | undefined, model: string | null | undefined): number;
|
|
8
|
+
export declare function calculateCost(inputTokens: number, outputTokens: number, model: string | null | undefined, cachedInputTokens?: number, _date?: Date): number;
|
|
9
|
+
export declare function resolveCost(costUsd: number | undefined, inputTokens: number | undefined, outputTokens: number | undefined, cachedInputTokens: number | undefined, model: string | null | undefined, date?: Date): number;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
export interface TimeoutConfig {
|
|
2
2
|
queryMs: number;
|
|
3
3
|
executeMs: number;
|
|
4
|
+
idleMs: number;
|
|
4
5
|
}
|
|
6
|
+
export declare const DEFAULT_IDLE_MS: number;
|
|
7
|
+
export declare function parseIdleEnvOverride(env?: NodeJS.ProcessEnv): number | undefined;
|
|
5
8
|
export declare function getProviderTimeoutConfig(env?: NodeJS.ProcessEnv): TimeoutConfig;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CrewxProjectConfig } from '../types';
|
|
2
|
+
export declare const DEFAULT_WI_BOARD_ID = "default";
|
|
3
|
+
export declare const ARCHIVE_WI_BOARD_ID = "archive";
|
|
4
|
+
export declare const DEFAULT_WI_WORKFLOW_ID = "wi-default-flow";
|
|
5
|
+
export declare const WI_PLAN_WORKFLOW_ID = "wi-plan-flow";
|
|
6
|
+
export declare const WI_DEFAULT_FLOW_FILENAME = "wi-default-flow.yaml";
|
|
7
|
+
export declare const WI_PLAN_FLOW_FILENAME = "wi-plan-flow.yaml";
|
|
8
|
+
export declare const WI_BOARD_ID_PATTERN: RegExp;
|
|
9
|
+
export declare function isReservedWiBoardId(id: string): boolean;
|
|
10
|
+
export interface ResolvedWiBoard {
|
|
11
|
+
id: string;
|
|
12
|
+
name: string;
|
|
13
|
+
workflowId: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
goalId?: string;
|
|
16
|
+
system: boolean;
|
|
17
|
+
readOnly: boolean;
|
|
18
|
+
}
|
|
19
|
+
export declare function resolveWiBoards(config: CrewxProjectConfig | undefined): ResolvedWiBoard[];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CommandRunner, GlobalCrewxInfo, ShortcutProgressEvent } from './types';
|
|
2
|
+
export interface DetectGlobalCrewxOptions {
|
|
3
|
+
env: NodeJS.ProcessEnv;
|
|
4
|
+
cwd: string;
|
|
5
|
+
run: CommandRunner;
|
|
6
|
+
}
|
|
7
|
+
export declare function detectGlobalCrewx(opts: DetectGlobalCrewxOptions): Promise<GlobalCrewxInfo>;
|
|
8
|
+
export interface EnsureGlobalCrewxOptions {
|
|
9
|
+
env: NodeJS.ProcessEnv;
|
|
10
|
+
cwd: string;
|
|
11
|
+
run: CommandRunner;
|
|
12
|
+
targetVersion: string;
|
|
13
|
+
currentInfo?: GlobalCrewxInfo;
|
|
14
|
+
installRoot?: string;
|
|
15
|
+
onProgress?: (event: ShortcutProgressEvent) => void;
|
|
16
|
+
}
|
|
17
|
+
export declare function ensureGlobalCrewx(opts: EnsureGlobalCrewxOptions): Promise<{
|
|
18
|
+
info: GlobalCrewxInfo;
|
|
19
|
+
}>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
export { getShortcutStatus, installShortcut, uninstallShortcut, dismissShortcutNotice, } from './install';
|
|
2
|
+
export { ShortcutError, type ShortcutState, type DesktopSource, type GlobalCrewxInfo, type ShortcutStatus, type ShortcutInstallResult, type ShortcutProgressPhase, type ShortcutProgressEvent, type ShortcutEnvOptions, type InstallShortcutOptions, type ShortcutErrorCode, type CommandResult, type CommandRunner, type CommandRunOptions, type ShortcutFsLike, } from './types';
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
'use strict';var d=require('path'),fs=require('fs'),os=require('os'),child_process=require('child_process'),module$1=require('module');function _interopNamespace(e){if(e&&e.__esModule)return e;var n=Object.create(null);if(e){Object.keys(e).forEach(function(k){if(k!=='default'){var d=Object.getOwnPropertyDescriptor(e,k);Object.defineProperty(n,k,d.get?d:{enumerable:true,get:function(){return e[k]}});}})}n.default=e;return Object.freeze(n)}var d__namespace=/*#__PURE__*/_interopNamespace(d);var O=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,n)=>(typeof require<"u"?require:e)[n]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var f=class extends Error{code;constructor(e,n){super(`${e}: ${n}`),this.code=e,this.name="ShortcutError";}};var F={existsSync:t=>fs.existsSync(t),readFileSync:t=>fs.readFileSync(t,"utf8"),writeFileSync:(t,e)=>fs.writeFileSync(t,e,"utf8"),mkdirSync:t=>{fs.mkdirSync(t,{recursive:true});},unlinkSync:t=>{fs.unlinkSync(t);}},$=os.homedir;function L(t){return typeof t!="string"?void 0:t.trim()||void 0}function k(t){return L(t)?.toLowerCase()??""}function R(t){try{return fs.statSync(t).isFile()}catch{return false}}function xt(t,e){if(t===e)return true;let n=d__namespace.default.relative(t,e);return n!==""&&!n.startsWith("..")&&!d__namespace.default.isAbsolute(n)}function Lt(t,e){if(d__namespace.default.basename(t)!==".bin")return false;let n=d__namespace.default.dirname(t);if(d__namespace.default.basename(n)!=="node_modules")return false;let r=d__namespace.default.dirname(n);return xt(r,e)}function V(t,e={}){if(t.includes("/")||t.includes("\\")||d__namespace.default.isAbsolute(t))return t;let n=e.platform??process.platform,r=e.env??process.env,s=d__namespace.default.resolve(e.cwd??process.cwd()),c=(e.resolution??"global_first")==="global_first",o=r.PATH??r.Path??process.env.PATH??process.env.Path??"",i=n==="win32"?";":":",a=o.split(i).map(u=>u.trim()).filter(Boolean),l=d__namespace.default.extname(t).length>0,h=r.PATHEXT??r.Pathext??process.env.PATHEXT??process.env.Pathext??".EXE;.CMD;.BAT;.COM",m=n==="win32"?l?[""]:h.split(";").map(u=>u.trim()).filter(Boolean).map(u=>u.startsWith(".")?u:`.${u}`):[""];for(let u of a){let p=d__namespace.default.resolve(s,u);if(!(c&&Lt(p,s)))for(let g of m){let mt=k(g),gt=g.toUpperCase();for(let wt of [g,mt,gt]){let M=d__namespace.default.join(p,`${t}${wt}`);if(R(M))return M}}}return t}function kt(t){if(!R(t))return null;try{let e=fs.readFileSync(t,"utf8"),n=d__namespace.default.dirname(t),r=[];for(let i of e.matchAll(/"([^"\r\n]*)"/g)){let h=(i[1]??"").match(/%~?dp0%?\s*[\\/]*(.*)$/i)?.[1]?.trim();if(!h)continue;let m=h.replace(/[\\/]+/g,d__namespace.default.sep).replace(/^[\\/]+/,""),u=d__namespace.default.resolve(n,m);R(u)&&r.push(u);}let s=[],c=new Map;for(let i of e.matchAll(/SET\s+"(\w+)=%~?dp0%?[\\/]?([^"]+)"/gi)){let a=i[1].toUpperCase(),l=i[2].trim().replace(/[\\/]+/g,d__namespace.default.sep).replace(/^[\\/]+/,"");c.set(a,d__namespace.default.resolve(n,l));}for(let i of e.split(/\r?\n/))if(i.includes("%*"))for(let a of i.matchAll(/"%(\w+)%"/g)){let l=c.get(a[1].toUpperCase());l&&R(l)&&s.push(l);}let o=i=>i.find(a=>{let l=k(d__namespace.default.basename(a));return l!=="node.exe"&&l!=="node"})??null;return o(s)??o(r)}catch{return null}}function It(t,e){if(typeof e=="string")return L(e)||null;if(!e||typeof e!="object")return null;if(t){let n=e[t],r=typeof n=="string"?L(n):void 0;if(r)return r}for(let n of Object.values(e)){let r=typeof n=="string"?L(n):void 0;if(r)return r}return null}function _t(t,e){if(!e)return null;let n=d__namespace.default.dirname(t),r=[d__namespace.default.resolve(n,"..",e),d__namespace.default.resolve(n,"node_modules",e)];for(let s of r){let c=d__namespace.default.join(s,"package.json");if(R(c))try{let o=JSON.parse(fs.readFileSync(c,"utf8")),i=It(e,o.bin);if(!i)continue;let a=d__namespace.default.resolve(s,i);if(R(a))return a}catch{}}return null}function Nt(t){let e=t.platform??process.platform,n=t.env??process.env,r=t.execPath??process.execPath,s=t.cwd,c=t.resolution;if(e!=="win32")return {command:V(t.command,{cwd:s,env:n,platform:e,resolution:c}),leadingArgv:[],resolution:"direct"};let o=V(t.command,{cwd:s,env:n,platform:e,resolution:c}),i=k(d__namespace.default.extname(o));if(i===".js"||i===".cjs"||i===".mjs")return {command:r,leadingArgv:[o],resolution:"node-entrypoint",windowsHide:true};if(i===".cmd"||i===".bat"){let a=kt(o)??_t(o,t.packageName);return a?k(d__namespace.default.extname(a))===".exe"?{command:a,leadingArgv:[],resolution:"exe-entrypoint",windowsHide:true}:{command:r,leadingArgv:[a],resolution:"node-entrypoint",windowsHide:true}:{command:o,leadingArgv:[],resolution:"unresolved-wrapper"}}return {command:o,leadingArgv:[],resolution:"direct"}}function Ot(t){if(t.candidate.resolution!=="unresolved-wrapper")return {command:t.candidate.command,leadingArgv:t.candidate.leadingArgv,resolution:t.candidate.resolution,windowsHide:t.candidate.windowsHide};throw new Error(`${d__namespace.default.basename(t.candidate.command)} wrapper resolved, but no executable/Node entrypoint could be resolved without shell execution.`)}function X(t){let e=Nt(t);return Ot({candidate:e})}function H(t,e){return {command:t.command,argv:[...t.leadingArgv,...e],resolution:t.resolution,shell:t.shell,windowsHide:t.windowsHide}}var G=3e4;function bt(t){if(typeof t.pid!="number"){t.kill();return}if(process.platform==="win32"){child_process.spawn("taskkill",["/pid",String(t.pid),"/t","/f"],{windowsHide:true}).on("error",()=>{});return}try{process.kill(-t.pid,"SIGKILL");}catch{t.kill("SIGKILL");}}var j=(t,e,n={})=>new Promise((r,s)=>{let c=n.env??process.env,o=process.platform,i;try{let p=X({command:t,platform:o,env:c,cwd:n.cwd,allowShellFallback:!1});i=H(p,e);}catch(p){s(p instanceof Error?p:new Error(String(p)));return}let a=child_process.spawn(i.command,i.argv,{cwd:n.cwd,env:c,shell:i.shell,windowsHide:i.windowsHide??true,detached:o!=="win32"}),l="",h="",m=false,u=setTimeout(()=>{m||(m=true,bt(a),s(new Error(`Command timed out after ${n.timeoutMs??G}ms: ${t} ${e.join(" ")}`)));},n.timeoutMs??G);a.stdout?.on("data",p=>{l+=p.toString();}),a.stderr?.on("data",p=>{h+=p.toString();}),a.on("error",p=>{m||(m=true,clearTimeout(u),s(p));}),a.on("close",p=>{m||(m=true,clearTimeout(u),r({code:p??0,stdout:l,stderr:h}));});});function Wt(){try{return (typeof O=="function"?O:module$1.createRequire(__filename)).resolve("@crewx/sdk/package.json")}catch{return null}}function Tt(){let t=[Wt(),d.join(__dirname,"../../package.json"),d.join(__dirname,"../../../package.json")].filter(e=>!!e);for(let e of t)try{let n=JSON.parse(fs.readFileSync(e,"utf8"));if(n.name==="@crewx/sdk"&&n.version)return n.version}catch{}return "0.0.0"}var K=Tt();var S=d__namespace.win32;function b(t){return S.join(t,".crewx")}function q(t){return S.join(b(t),"shortcut.json")}function Q(t){return S.join(b(t),"launcher.json")}function Y(t){return S.join(b(t),"bin","crewx-launcher.cmd")}function Z(t){return S.join(t,"CrewX.lnk")}function D(t,e){return S.normalize(t).toLowerCase()===S.normalize(e).toLowerCase()}var Mt="[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; [Environment]::GetFolderPath('DesktopDirectory')";async function tt(t){try{let n=await t.run("powershell",["-NoProfile","-NonInteractive","-Command",Mt],{env:t.env}),r=n.stdout.trim();if(n.code===0&&r)return {dir:r,source:"known-folder"}}catch{}let e=t.env.USERPROFILE||t.env.Userprofile||t.homedir();return e?{dir:S.join(e,"Desktop"),source:"fallback"}:null}function A(t,e){let n=S.resolve(e,"node_modules",".bin").toLowerCase();return t.split(";").filter(r=>r?S.resolve(r).toLowerCase()!==n:true).join(";")}function et(t){return t?/\\Program Files( \(x86\))?\\/i.test(t)&&/crewx/i.test(t):false}function Ft(t,e){let n=a=>{let[l,...h]=a.split("-"),m=h.join("-")||void 0;return {parts:(l??"").split(".").map(p=>Number.parseInt(p,10)||0),pre:m}},r=n(t),s=n(e),c=Math.max(r.parts.length,s.parts.length);for(let a=0;a<c;a++){let l=r.parts[a]??0,h=s.parts[a]??0;if(l!==h)return l<h?-1:1}if(r.pre===s.pre)return 0;if(!r.pre&&s.pre)return 1;if(r.pre&&!s.pre)return -1;let o=Number.parseInt(r.pre.match(/(\d+)$/)?.[1]??"",10),i=Number.parseInt(s.pre.match(/(\d+)$/)?.[1]??"",10);return !Number.isNaN(o)&&!Number.isNaN(i)&&o!==i?o<i?-1:1:r.pre<s.pre?-1:r.pre>s.pre?1:0}function v(t,e){return Ft(t,e)<0}var rt=d__namespace.win32,ot=1;function st(t,e){if(!t.existsSync(e))return null;try{let n=JSON.parse(t.readFileSync(e));return {schema:n.schema??ot,shortcutPath:n.shortcutPath,version:n.version,owned:!!n.owned,declined:!!n.declined,desktopSource:n.desktopSource,updatedAt:n.updatedAt}}catch{return null}}function I(t,e,n){let r={schema:ot,...n,updatedAt:new Date().toISOString()};t.mkdirSync(rt.dirname(e)),t.writeFileSync(e,JSON.stringify(r,null,2));}function _(t,e){if(!t.existsSync(e))return null;try{let n=JSON.parse(t.readFileSync(e));return {schema:n.schema??0,binPath:n.binPath,updatedAt:n.updatedAt}}catch{return null}}function it(t,e,n){t.mkdirSync(rt.dirname(e)),t.writeFileSync(e,JSON.stringify(n,null,2));}var $t=d__namespace.win32,y=1;function Vt(t){return t.replace(/%/g,"%%")}function Bt(t){return ["@echo off","setlocal DisableDelayedExpansion","chcp 65001 >nul","",'set "CREWX_WORKDIR=%USERPROFILE%\\crewx"','if not exist "%CREWX_WORKDIR%" mkdir "%CREWX_WORKDIR%" >nul 2>nul','cd /d "%CREWX_WORKDIR%"',"",'set "CREWX_PORT_EFFECTIVE=%CREWX_PORT%"','if "%CREWX_PORT_EFFECTIVE%"=="" set "CREWX_PORT_EFFECTIVE=8150"','set "CREWX_HEALTH_URL=http://127.0.0.1:%CREWX_PORT_EFFECTIVE%/api/v1/health"','set "CREWX_ORIGIN_URL=http://127.0.0.1:%CREWX_PORT_EFFECTIVE%/"',"",t.bakedBinPath?`set "CREWX_FALLBACK_BIN=${Vt(t.bakedBinPath)}"`:'set "CREWX_FALLBACK_BIN="','set "CREWX_RESOLVED_BIN=%CREWX_BIN%"','if "%CREWX_RESOLVED_BIN%"=="" set "CREWX_RESOLVED_BIN=%CREWX_FALLBACK_BIN%"','if "%CREWX_RESOLVED_BIN%"=="" (',` for /f "delims=" %%I in ('where crewx 2^>nul') do (`,' if not defined CREWX_RESOLVED_BIN set "CREWX_RESOLVED_BIN=%%I"'," )",")","",'powershell -NoProfile -NonInteractive -Command "try { $r = Invoke-WebRequest -Uri $env:CREWX_HEALTH_URL -TimeoutSec 1 -UseBasicParsing; if ($r.StatusCode -eq 200) { exit 0 } else { exit 1 } } catch { exit 1 }"',"if %ERRORLEVEL% EQU 0 (",' start "" "%CREWX_ORIGIN_URL%"'," exit /b 0",")","",'if "%CREWX_RESOLVED_BIN%"=="" ('," echo CrewX executable not found. Please reinstall the desktop shortcut."," pause"," exit /b 1",")","",'start "CrewX" /min "%CREWX_RESOLVED_BIN%"',""].join(`\r
|
|
2
|
+
`)}function ct(t){let e=_(t.fs,t.launcherManifestPath),n=!!e&&e.schema>=y&&t.fs.existsSync(t.wrapperPath),r=n&&!e.binPath&&!!t.bakedBinPath;if(n&&!r)return {wrapperPath:t.wrapperPath,wrote:false,schema:e.schema};let c=Bt({bakedBinPath:t.bakedBinPath});try{t.fs.mkdirSync($t.dirname(t.wrapperPath)),t.fs.writeFileSync(t.wrapperPath,c),it(t.fs,t.launcherManifestPath,{schema:y,binPath:t.bakedBinPath,updatedAt:new Date().toISOString()});}catch(o){throw o instanceof f?o:new f("WRITE_DENIED",`Could not write launcher wrapper: ${o instanceof Error?o.message:String(o)}`)}return {wrapperPath:t.wrapperPath,wrote:true,schema:y}}var Xt=["$ws = New-Object -ComObject WScript.Shell","$sc = $ws.CreateShortcut($env:CREWX_LNK_PATH)","$sc.TargetPath = $env:CREWX_LNK_TARGET","if ($env:CREWX_LNK_WORKDIR) { $sc.WorkingDirectory = $env:CREWX_LNK_WORKDIR }","$sc.WindowStyle = 7","if ($env:CREWX_LNK_ICON) { $sc.IconLocation = $env:CREWX_LNK_ICON }","$sc.Save()"].join("; "),Ht=["[Console]::OutputEncoding = [System.Text.Encoding]::UTF8","$ws = New-Object -ComObject WScript.Shell","$sc = $ws.CreateShortcut($env:CREWX_LNK_PATH)","[PSCustomObject]@{ TargetPath = $sc.TargetPath; WorkingDirectory = $sc.WorkingDirectory; IconLocation = $sc.IconLocation } | ConvertTo-Json -Compress"].join("; ");async function lt(t){let e={...t.env,CREWX_LNK_PATH:t.shortcutPath,CREWX_LNK_TARGET:t.targetPath,CREWX_LNK_WORKDIR:t.workingDirectory??"",CREWX_LNK_ICON:t.iconPath??""},n;try{n=await t.run("powershell",["-NoProfile","-NonInteractive","-Command",Xt],{env:e});}catch(r){throw new f("POWERSHELL_UNAVAILABLE",`Could not run PowerShell: ${r instanceof Error?r.message:String(r)}`)}if(n.code!==0)throw new f("POWERSHELL_UNAVAILABLE",`Failed to create desktop shortcut: ${n.stderr||n.stdout}`)}function ut(t){let e=t.trim(),n=e.lastIndexOf(",");return n!==-1&&/^-?\d+$/.test(e.slice(n+1).trim())&&(e=e.slice(0,n).trim()),e.length>=2&&e.startsWith('"')&&e.endsWith('"')&&(e=e.slice(1,-1).trim()),e}async function dt(t){try{let e={...t.env,CREWX_LNK_PATH:t.shortcutPath},n=await t.run("powershell",["-NoProfile","-NonInteractive","-Command",Ht],{env:e});if(n.code!==0||!n.stdout.trim())return null;let r=JSON.parse(n.stdout.trim());return {targetPath:r.TargetPath??"",workingDirectory:r.WorkingDirectory??"",iconLocation:r.IconLocation??""}}catch{return null}}var T=d__namespace.win32;async function C(t){let e=A(t.env.PATH??t.env.Path??"",t.cwd),n={...t.env,PATH:e,Path:e},r;try{r=await t.run("npm",["list","-g","crewx","--depth=0","--json"],{env:n});}catch{return {installed:false}}let s;try{s=JSON.parse(r.stdout||"{}");}catch{return {installed:false}}let c=s.dependencies?.crewx;if(!c?.version)return {installed:false};let o;try{let a=await t.run("npm",["prefix","-g"],{env:n});a.code===0&&(o=a.stdout.trim()||void 0);}catch{}let i=o?T.join(o,"crewx.cmd"):void 0;return {installed:true,version:c.version,binPath:i,prefix:o}}var Gt=/EACCES|EPERM|EROFS/,Ut=/ENOTFOUND|ETIMEDOUT|ECONNREFUSED|network|registry/i,jt=/^\d+\.\d+\.\d+/;function Jt(t){return !!t&&t!=="0.0.0"&&jt.test(t)}var W=10*6e4;async function ft(t){if(!Jt(t.targetVersion))throw new f("GLOBAL_INSTALL_FAILED",`RUNNING_VERSION_UNKNOWN: cannot reliably determine the running crewx version to install (got ${JSON.stringify(t.targetVersion)}); refusing to fall back to crewx@latest`);if(t.currentInfo?.installed&&t.currentInfo.version&&!v(t.currentInfo.version,t.targetVersion))return {info:t.currentInfo};let e=A(t.env.PATH??t.env.Path??"",t.cwd),n={...t.env,PATH:e,Path:e},r=`crewx@${t.targetVersion}`;t.onProgress?.({phase:"global-install",message:`Installing crewx globally (npm install -g ${r})`});let s;try{s=await t.run("npm",["install","-g",r,"--no-audit","--no-fund"],{env:n,timeoutMs:W});}catch(o){throw new f("NPM_UNAVAILABLE",`Could not run npm: ${o instanceof Error?o.message:String(o)}`)}if(s.code===0)return {info:await C({env:n,cwd:t.cwd,run:t.run})};let c=`${s.stdout}
|
|
3
|
+
${s.stderr}`;if(Gt.test(c)){t.onProgress?.({phase:"global-install",message:"Permission denied \u2014 retrying with a user-scoped npm prefix"});let o=t.env.LOCALAPPDATA||T.join(t.env.USERPROFILE??"","AppData","Local"),i={...n,npm_config_prefix:T.join(o,"crewx","npm")},a;try{a=await t.run("npm",["install","-g",r,"--no-audit","--no-fund"],{env:i,timeoutMs:W});}catch(l){throw new f("NPM_PERMISSION_DENIED",`Retry with user-scoped prefix failed: ${l instanceof Error?l.message:String(l)}`)}if(a.code===0)return {info:await C({env:i,cwd:t.cwd,run:t.run})};throw new f("NPM_PERMISSION_DENIED",`npm install -g failed after user-scoped prefix retry: ${a.stderr||a.stdout}`)}if(Ut.test(c)){if(!t.installRoot)throw new f("OFFLINE_NO_SOURCE","The npm registry is unreachable and no local installRoot was provided for an offline install");t.onProgress?.({phase:"global-install",message:`Registry unreachable \u2014 installing offline from ${t.installRoot}`});let o;try{o=await t.run("npm",["install","-g",t.installRoot,"--offline","--no-audit","--no-fund"],{env:n,timeoutMs:W});}catch(i){throw new f("GLOBAL_INSTALL_FAILED",`Offline install failed: ${i instanceof Error?i.message:String(i)}`)}if(o.code===0)return {info:await C({env:n,cwd:t.cwd,run:t.run})};throw new f("GLOBAL_INSTALL_FAILED",`Offline install failed: ${o.stderr||o.stdout}`)}throw new f("GLOBAL_INSTALL_FAILED",c.trim()||`npm install -g ${r} failed`)}function Kt(t){return t.run??j}function zt(t){return t.fs??F}async function N(t){let e=t.platform??process.platform,n=t.env??process.env,r=t.homedir??$,s=Kt(t),c=zt(t),o=t.runningVersion??K,i=t.cwd??process.cwd(),a=r(),l=q(a),h=Q(a),m=Y(a),u=null;e==="win32"&&(u=await tt({env:n,homedir:r,run:s}));let p=u?Z(u.dir):null;return {platform:e,env:n,homedir:r,run:s,fs:c,runningVersion:o,cwd:i,installRoot:t.installRoot,shortcutManifestPath:l,launcherManifestPath:h,wrapperPath:m,desktop:u,shortcutPath:p}}function qt(t){return t?d__namespace.win32.normalize(t).toLowerCase().endsWith(`${d__namespace.win32.sep}bin${d__namespace.win32.sep}crewx.ico`):false}async function P(t){if(t.platform!=="win32")return {supported:false,state:"unsupported",globalCrewx:null,runningVersion:t.runningVersion,errors:[],manifest:null,iconStale:false};let e=[];t.desktop||e.push("NO_DESKTOP_DIR: could not resolve the Windows Desktop directory");let n=st(t.fs,t.shortcutManifestPath),r=_(t.fs,t.launcherManifestPath),s=await C({env:t.env,cwd:t.cwd,run:t.run}),c=t.shortcutPath?t.fs.existsSync(t.shortcutPath):false,o,i=false;if(!c)o=n?.declined?"declined":"not-installed";else {let a=!!n?.owned&&!!t.shortcutPath&&n.shortcutPath===t.shortcutPath,l=false,h=t.shortcutPath?await dt({run:t.run,env:t.env,shortcutPath:t.shortcutPath}):null;if(a||(h&&D(h.targetPath,t.wrapperPath)?a=true:h&&et(h.targetPath)&&(l=true)),l)o="foreign",e.push("NSIS_PRESENT: an NSIS-installed CrewX shortcut was detected");else if(!a)o="foreign";else if(n?.version&&v(t.runningVersion,n.version))o="superseded",e.push(`SUPERSEDED: running version ${t.runningVersion} is older than the installed shortcut's version ${n.version}; refusing to modify it`);else {let m=!r||r.schema<y||!t.fs.existsSync(t.wrapperPath);if(h){let u=ut(h.iconLocation);if(!(!!u&&t.fs.existsSync(u)))i=true;else {let g=ht(s,t.fs);g?i=!D(u,g):i=!qt(u);}}o=m||i?"stale":"installed";}}return {supported:true,state:o,shortcutPath:t.shortcutPath??void 0,desktopDir:t.desktop?.dir,desktopSource:t.desktop?.source,wrapperPath:t.wrapperPath,wrapperSchema:r?.schema,globalCrewx:s.installed?s:{installed:false},runningVersion:t.runningVersion,errors:e,manifest:n,iconStale:i}}function ht(t,e){if(!t?.installed||!t.prefix)return;let n=d__namespace.win32.join(t.prefix,"node_modules","crewx","bin","crewx.ico");return e.existsSync(n)?n:void 0}function E(t){let{manifest:e,iconStale:n,...r}=t;return r}async function Qt(t={}){let e=await N(t),n=await P(e);return E(n)}async function Yt(t={}){let e=await N(t);t.onProgress?.({phase:"detect",message:"Checking current shortcut status"});let n=await P(e),r=E(n);if(!r.supported)return {...r,changed:false,installedGlobal:false};if(r.state==="superseded")return {...r,changed:false,installedGlobal:false};if(r.state==="foreign"){if(n.errors.some(g=>g.startsWith("NSIS_PRESENT")))throw new f("NSIS_PRESENT",`An NSIS-installed CrewX shortcut was detected at ${r.shortcutPath}`);if(!t.force)throw new f("FOREIGN_SHORTCUT",`An existing shortcut at ${r.shortcutPath} is not managed by CrewX`)}if(!e.desktop||!e.shortcutPath)throw new f("NO_DESKTOP_DIR","Could not resolve the Windows Desktop directory");let s=false,c=false,o=r.globalCrewx,i=[];if(!!o?.installed&&!!o.version&&v(o.version,e.runningVersion)||!o?.installed&&r.state!=="installed"){let g=await ft({env:e.env,cwd:e.cwd,run:e.run,targetVersion:e.runningVersion,currentInfo:o??void 0,installRoot:e.installRoot,onProgress:t.onProgress});o=g.info,c=g.info.installed,s=true,c||i.push(`GLOBAL_INSTALL_UNCONFIRMED: npm install -g crewx@${e.runningVersion} exited successfully but a follow-up check could not confirm the global install`);}if(t.onProgress?.({phase:"wrapper",message:"Ensuring launcher wrapper"}),ct({fs:e.fs,wrapperPath:e.wrapperPath,launcherManifestPath:e.launcherManifestPath,bakedBinPath:o?.binPath}).wrote&&(s=true),!((r.state==="installed"||r.state==="stale")&&!n.iconStale)){let g=ht(o,e.fs);if(n.iconStale&&!g)throw new f("ICON_UNAVAILABLE",`Could not locate the global CrewX icon (bin\\crewx.ico) to repair the desktop shortcut at ${e.shortcutPath}; the existing shortcut was left untouched`);t.onProgress?.({phase:"lnk",message:"Creating desktop shortcut"}),await lt({run:e.run,env:e.env,shortcutPath:e.shortcutPath,targetPath:e.wrapperPath,iconPath:g}),s=true;}s&&I(e.fs,e.shortcutManifestPath,{shortcutPath:e.shortcutPath,version:e.runningVersion,owned:true,declined:false,desktopSource:e.desktop.source});let u=await P(e),p=E(u);return {...p,errors:[...p.errors,...i],changed:s,installedGlobal:c}}async function Zt(t={}){let e=await N(t),n=await P(e),r=E(n);if(!r.supported)return r;if((r.state==="installed"||r.state==="stale")&&e.shortcutPath)try{e.fs.unlinkSync(e.shortcutPath);}catch{}I(e.fs,e.shortcutManifestPath,{shortcutPath:void 0,version:n.manifest?.version,owned:false,declined:true,desktopSource:void 0});let s=await P(e);return E(s)}async function te(t={}){let e=await N(t),n=await P(e),r=E(n);if(!r.supported)return r;I(e.fs,e.shortcutManifestPath,{shortcutPath:n.manifest?.shortcutPath,version:n.manifest?.version,owned:n.manifest?.owned??false,declined:true,desktopSource:n.manifest?.desktopSource});let s=await P(e);return E(s)}exports.ShortcutError=f;exports.dismissShortcutNotice=te;exports.getShortcutStatus=Qt;exports.installShortcut=Yt;exports.uninstallShortcut=Zt;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type InstallShortcutOptions, type ShortcutEnvOptions, type ShortcutInstallResult, type ShortcutStatus } from './types';
|
|
2
|
+
export declare function getShortcutStatus(options?: ShortcutEnvOptions): Promise<ShortcutStatus>;
|
|
3
|
+
export declare function installShortcut(options?: InstallShortcutOptions): Promise<ShortcutInstallResult>;
|
|
4
|
+
export declare function uninstallShortcut(options?: ShortcutEnvOptions): Promise<ShortcutStatus>;
|
|
5
|
+
export declare function dismissShortcutNotice(options?: ShortcutEnvOptions): Promise<ShortcutStatus>;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { CommandRunner } from './types';
|
|
2
|
+
export interface WriteLnkOptions {
|
|
3
|
+
run: CommandRunner;
|
|
4
|
+
env: NodeJS.ProcessEnv;
|
|
5
|
+
shortcutPath: string;
|
|
6
|
+
targetPath: string;
|
|
7
|
+
workingDirectory?: string;
|
|
8
|
+
iconPath?: string;
|
|
9
|
+
}
|
|
10
|
+
export declare function writeLnk(opts: WriteLnkOptions): Promise<void>;
|
|
11
|
+
export interface LnkInfo {
|
|
12
|
+
targetPath: string;
|
|
13
|
+
workingDirectory: string;
|
|
14
|
+
iconLocation: string;
|
|
15
|
+
}
|
|
16
|
+
export interface ReadLnkOptions {
|
|
17
|
+
run: CommandRunner;
|
|
18
|
+
env: NodeJS.ProcessEnv;
|
|
19
|
+
shortcutPath: string;
|
|
20
|
+
}
|
|
21
|
+
export declare function normalizeIconLocation(raw: string): string;
|
|
22
|
+
export declare function readLnkTarget(opts: ReadLnkOptions): Promise<LnkInfo | null>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { DesktopSource, ShortcutFsLike } from './types';
|
|
2
|
+
export declare const MANIFEST_SCHEMA_VERSION = 1;
|
|
3
|
+
export interface ShortcutManifest {
|
|
4
|
+
schema: number;
|
|
5
|
+
shortcutPath?: string;
|
|
6
|
+
version?: string;
|
|
7
|
+
owned: boolean;
|
|
8
|
+
declined: boolean;
|
|
9
|
+
desktopSource?: DesktopSource;
|
|
10
|
+
updatedAt?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface LauncherManifest {
|
|
13
|
+
schema: number;
|
|
14
|
+
binPath?: string;
|
|
15
|
+
updatedAt?: string;
|
|
16
|
+
}
|
|
17
|
+
export declare function readShortcutManifest(fs: ShortcutFsLike, manifestPath: string): ShortcutManifest | null;
|
|
18
|
+
export declare function writeShortcutManifest(fs: ShortcutFsLike, manifestPath: string, data: Omit<ShortcutManifest, 'schema' | 'updatedAt'>): void;
|
|
19
|
+
export declare function readLauncherManifest(fs: ShortcutFsLike, manifestPath: string): LauncherManifest | null;
|
|
20
|
+
export declare function writeLauncherManifest(fs: ShortcutFsLike, manifestPath: string, data: LauncherManifest): void;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
export type ShortcutState = 'unsupported' | 'not-installed' | 'installed' | 'stale' | 'foreign' | 'superseded' | 'declined';
|
|
2
|
+
export type DesktopSource = 'known-folder' | 'fallback';
|
|
3
|
+
export interface GlobalCrewxInfo {
|
|
4
|
+
installed: boolean;
|
|
5
|
+
version?: string;
|
|
6
|
+
binPath?: string;
|
|
7
|
+
prefix?: string;
|
|
8
|
+
}
|
|
9
|
+
export interface ShortcutStatus {
|
|
10
|
+
supported: boolean;
|
|
11
|
+
state: ShortcutState;
|
|
12
|
+
shortcutPath?: string;
|
|
13
|
+
desktopDir?: string;
|
|
14
|
+
desktopSource?: DesktopSource;
|
|
15
|
+
wrapperPath?: string;
|
|
16
|
+
wrapperSchema?: number;
|
|
17
|
+
globalCrewx: GlobalCrewxInfo | null;
|
|
18
|
+
runningVersion: string;
|
|
19
|
+
errors: string[];
|
|
20
|
+
}
|
|
21
|
+
export interface ShortcutInstallResult extends ShortcutStatus {
|
|
22
|
+
changed: boolean;
|
|
23
|
+
installedGlobal: boolean;
|
|
24
|
+
}
|
|
25
|
+
export type ShortcutProgressPhase = 'detect' | 'global-install' | 'wrapper' | 'lnk';
|
|
26
|
+
export interface ShortcutProgressEvent {
|
|
27
|
+
phase: ShortcutProgressPhase;
|
|
28
|
+
message: string;
|
|
29
|
+
}
|
|
30
|
+
export interface CommandResult {
|
|
31
|
+
code: number;
|
|
32
|
+
stdout: string;
|
|
33
|
+
stderr: string;
|
|
34
|
+
}
|
|
35
|
+
export interface CommandRunOptions {
|
|
36
|
+
env?: NodeJS.ProcessEnv;
|
|
37
|
+
cwd?: string;
|
|
38
|
+
timeoutMs?: number;
|
|
39
|
+
}
|
|
40
|
+
export type CommandRunner = (command: string, args: string[], opts?: CommandRunOptions) => Promise<CommandResult>;
|
|
41
|
+
export interface ShortcutFsLike {
|
|
42
|
+
existsSync(path: string): boolean;
|
|
43
|
+
readFileSync(path: string): string;
|
|
44
|
+
writeFileSync(path: string, data: string): void;
|
|
45
|
+
mkdirSync(path: string): void;
|
|
46
|
+
unlinkSync(path: string): void;
|
|
47
|
+
}
|
|
48
|
+
export interface ShortcutEnvOptions {
|
|
49
|
+
platform?: NodeJS.Platform;
|
|
50
|
+
env?: NodeJS.ProcessEnv;
|
|
51
|
+
homedir?: () => string;
|
|
52
|
+
run?: CommandRunner;
|
|
53
|
+
fs?: ShortcutFsLike;
|
|
54
|
+
runningVersion?: string;
|
|
55
|
+
cwd?: string;
|
|
56
|
+
}
|
|
57
|
+
export interface InstallShortcutOptions extends ShortcutEnvOptions {
|
|
58
|
+
force?: boolean;
|
|
59
|
+
onProgress?: (event: ShortcutProgressEvent) => void;
|
|
60
|
+
installRoot?: string;
|
|
61
|
+
}
|
|
62
|
+
export type ShortcutErrorCode = 'NOT_WINDOWS' | 'NO_DESKTOP_DIR' | 'NPM_UNAVAILABLE' | 'NPM_PERMISSION_DENIED' | 'OFFLINE_NO_SOURCE' | 'GLOBAL_INSTALL_FAILED' | 'POWERSHELL_UNAVAILABLE' | 'WRITE_DENIED' | 'FOREIGN_SHORTCUT' | 'NSIS_PRESENT' | 'ICON_UNAVAILABLE';
|
|
63
|
+
export declare class ShortcutError extends Error {
|
|
64
|
+
readonly code: ShortcutErrorCode;
|
|
65
|
+
constructor(code: ShortcutErrorCode, message: string);
|
|
66
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const SDK_VERSION: string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CommandRunner, DesktopSource } from './types';
|
|
2
|
+
export declare function crewxHomeDir(homedir: string): string;
|
|
3
|
+
export declare function shortcutManifestPath(homedir: string): string;
|
|
4
|
+
export declare function launcherManifestPath(homedir: string): string;
|
|
5
|
+
export declare function wrapperPath(homedir: string): string;
|
|
6
|
+
export declare function shortcutLnkPath(desktopDir: string): string;
|
|
7
|
+
export declare function samePath(a: string, b: string): boolean;
|
|
8
|
+
export interface ResolveDesktopDirOptions {
|
|
9
|
+
env: NodeJS.ProcessEnv;
|
|
10
|
+
homedir: () => string;
|
|
11
|
+
run: CommandRunner;
|
|
12
|
+
}
|
|
13
|
+
export interface ResolvedDesktopDir {
|
|
14
|
+
dir: string;
|
|
15
|
+
source: DesktopSource;
|
|
16
|
+
}
|
|
17
|
+
export declare function resolveDesktopDir(opts: ResolveDesktopDirOptions): Promise<ResolvedDesktopDir | null>;
|
|
18
|
+
export declare function filterWorkspaceLocalBin(pathValue: string, cwd: string): string;
|
|
19
|
+
export declare function looksLikeNsisInstall(targetPath: string): boolean;
|
|
20
|
+
export declare function compareVersions(a: string, b: string): -1 | 0 | 1;
|
|
21
|
+
export declare function isOlderVersion(a: string, b: string): boolean;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ShortcutFsLike } from './types';
|
|
2
|
+
export declare const WRAPPER_SCHEMA_VERSION = 1;
|
|
3
|
+
export interface BuildWrapperScriptOptions {
|
|
4
|
+
bakedBinPath?: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function buildWrapperScript(opts: BuildWrapperScriptOptions): string;
|
|
7
|
+
export interface EnsureWrapperOptions {
|
|
8
|
+
fs: ShortcutFsLike;
|
|
9
|
+
wrapperPath: string;
|
|
10
|
+
launcherManifestPath: string;
|
|
11
|
+
bakedBinPath?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface EnsureWrapperResult {
|
|
14
|
+
wrapperPath: string;
|
|
15
|
+
wrote: boolean;
|
|
16
|
+
schema: number;
|
|
17
|
+
}
|
|
18
|
+
export declare function ensureWrapper(opts: EnsureWrapperOptions): EnsureWrapperResult;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import*as d from'path';import d__default,{join}from'path';import {fileURLToPath}from'url';import {readFileSync,unlinkSync,mkdirSync,writeFileSync,existsSync,statSync}from'fs';import {homedir}from'os';import {spawn}from'child_process';import {createRequire}from'module';var b=(t=>typeof require<"u"?require:typeof Proxy<"u"?new Proxy(t,{get:(e,n)=>(typeof require<"u"?require:e)[n]}):t)(function(t){if(typeof require<"u")return require.apply(this,arguments);throw Error('Dynamic require of "'+t+'" is not supported')});var $=()=>fileURLToPath(import.meta.url),vt=()=>d__default.dirname($()),w=vt(),S=$();var f=class extends Error{code;constructor(e,n){super(`${e}: ${n}`),this.code=e,this.name="ShortcutError";}};var V={existsSync:t=>existsSync(t),readFileSync:t=>readFileSync(t,"utf8"),writeFileSync:(t,e)=>writeFileSync(t,e,"utf8"),mkdirSync:t=>{mkdirSync(t,{recursive:true});},unlinkSync:t=>{unlinkSync(t);}},B=homedir;function k(t){return typeof t!="string"?void 0:t.trim()||void 0}function I(t){return k(t)?.toLowerCase()??""}function v(t){try{return statSync(t).isFile()}catch{return false}}function _t(t,e){if(t===e)return true;let n=d__default.relative(t,e);return n!==""&&!n.startsWith("..")&&!d__default.isAbsolute(n)}function Ot(t,e){if(d__default.basename(t)!==".bin")return false;let n=d__default.dirname(t);if(d__default.basename(n)!=="node_modules")return false;let r=d__default.dirname(n);return _t(r,e)}function X(t,e={}){if(t.includes("/")||t.includes("\\")||d__default.isAbsolute(t))return t;let n=e.platform??process.platform,r=e.env??process.env,s=d__default.resolve(e.cwd??process.cwd()),c=(e.resolution??"global_first")==="global_first",o=r.PATH??r.Path??process.env.PATH??process.env.Path??"",i=n==="win32"?";":":",a=o.split(i).map(u=>u.trim()).filter(Boolean),l=d__default.extname(t).length>0,h=r.PATHEXT??r.Pathext??process.env.PATHEXT??process.env.Pathext??".EXE;.CMD;.BAT;.COM",m=n==="win32"?l?[""]:h.split(";").map(u=>u.trim()).filter(Boolean).map(u=>u.startsWith(".")?u:`.${u}`):[""];for(let u of a){let p=d__default.resolve(s,u);if(!(c&&Ot(p,s)))for(let g of m){let wt=I(g),St=g.toUpperCase();for(let Pt of [g,wt,St]){let F=d__default.join(p,`${t}${Pt}`);if(v(F))return F}}}return t}function bt(t){if(!v(t))return null;try{let e=readFileSync(t,"utf8"),n=d__default.dirname(t),r=[];for(let i of e.matchAll(/"([^"\r\n]*)"/g)){let h=(i[1]??"").match(/%~?dp0%?\s*[\\/]*(.*)$/i)?.[1]?.trim();if(!h)continue;let m=h.replace(/[\\/]+/g,d__default.sep).replace(/^[\\/]+/,""),u=d__default.resolve(n,m);v(u)&&r.push(u);}let s=[],c=new Map;for(let i of e.matchAll(/SET\s+"(\w+)=%~?dp0%?[\\/]?([^"]+)"/gi)){let a=i[1].toUpperCase(),l=i[2].trim().replace(/[\\/]+/g,d__default.sep).replace(/^[\\/]+/,"");c.set(a,d__default.resolve(n,l));}for(let i of e.split(/\r?\n/))if(i.includes("%*"))for(let a of i.matchAll(/"%(\w+)%"/g)){let l=c.get(a[1].toUpperCase());l&&v(l)&&s.push(l);}let o=i=>i.find(a=>{let l=I(d__default.basename(a));return l!=="node.exe"&&l!=="node"})??null;return o(s)??o(r)}catch{return null}}function Dt(t,e){if(typeof e=="string")return k(e)||null;if(!e||typeof e!="object")return null;if(t){let n=e[t],r=typeof n=="string"?k(n):void 0;if(r)return r}for(let n of Object.values(e)){let r=typeof n=="string"?k(n):void 0;if(r)return r}return null}function At(t,e){if(!e)return null;let n=d__default.dirname(t),r=[d__default.resolve(n,"..",e),d__default.resolve(n,"node_modules",e)];for(let s of r){let c=d__default.join(s,"package.json");if(v(c))try{let o=JSON.parse(readFileSync(c,"utf8")),i=Dt(e,o.bin);if(!i)continue;let a=d__default.resolve(s,i);if(v(a))return a}catch{}}return null}function Wt(t){let e=t.platform??process.platform,n=t.env??process.env,r=t.execPath??process.execPath,s=t.cwd,c=t.resolution;if(e!=="win32")return {command:X(t.command,{cwd:s,env:n,platform:e,resolution:c}),leadingArgv:[],resolution:"direct"};let o=X(t.command,{cwd:s,env:n,platform:e,resolution:c}),i=I(d__default.extname(o));if(i===".js"||i===".cjs"||i===".mjs")return {command:r,leadingArgv:[o],resolution:"node-entrypoint",windowsHide:true};if(i===".cmd"||i===".bat"){let a=bt(o)??At(o,t.packageName);return a?I(d__default.extname(a))===".exe"?{command:a,leadingArgv:[],resolution:"exe-entrypoint",windowsHide:true}:{command:r,leadingArgv:[a],resolution:"node-entrypoint",windowsHide:true}:{command:o,leadingArgv:[],resolution:"unresolved-wrapper"}}return {command:o,leadingArgv:[],resolution:"direct"}}function Tt(t){if(t.candidate.resolution!=="unresolved-wrapper")return {command:t.candidate.command,leadingArgv:t.candidate.leadingArgv,resolution:t.candidate.resolution,windowsHide:t.candidate.windowsHide};throw new Error(`${d__default.basename(t.candidate.command)} wrapper resolved, but no executable/Node entrypoint could be resolved without shell execution.`)}function G(t){let e=Wt(t);return Tt({candidate:e})}function U(t,e){return {command:t.command,argv:[...t.leadingArgv,...e],resolution:t.resolution,shell:t.shell,windowsHide:t.windowsHide}}var j=3e4;function Mt(t){if(typeof t.pid!="number"){t.kill();return}if(process.platform==="win32"){spawn("taskkill",["/pid",String(t.pid),"/t","/f"],{windowsHide:true}).on("error",()=>{});return}try{process.kill(-t.pid,"SIGKILL");}catch{t.kill("SIGKILL");}}var K=(t,e,n={})=>new Promise((r,s)=>{let c=n.env??process.env,o=process.platform,i;try{let p=G({command:t,platform:o,env:c,cwd:n.cwd,allowShellFallback:!1});i=U(p,e);}catch(p){s(p instanceof Error?p:new Error(String(p)));return}let a=spawn(i.command,i.argv,{cwd:n.cwd,env:c,shell:i.shell,windowsHide:i.windowsHide??true,detached:o!=="win32"}),l="",h="",m=false,u=setTimeout(()=>{m||(m=true,Mt(a),s(new Error(`Command timed out after ${n.timeoutMs??j}ms: ${t} ${e.join(" ")}`)));},n.timeoutMs??j);a.stdout?.on("data",p=>{l+=p.toString();}),a.stderr?.on("data",p=>{h+=p.toString();}),a.on("error",p=>{m||(m=true,clearTimeout(u),s(p));}),a.on("close",p=>{m||(m=true,clearTimeout(u),r({code:p??0,stdout:l,stderr:h}));});});function Vt(){try{return (typeof b=="function"?b:createRequire(S)).resolve("@crewx/sdk/package.json")}catch{return null}}function Bt(){let t=[Vt(),join(w,"../../package.json"),join(w,"../../../package.json")].filter(e=>!!e);for(let e of t)try{let n=JSON.parse(readFileSync(e,"utf8"));if(n.name==="@crewx/sdk"&&n.version)return n.version}catch{}return "0.0.0"}var q=Bt();var P=d.win32;function D(t){return P.join(t,".crewx")}function Y(t){return P.join(D(t),"shortcut.json")}function Z(t){return P.join(D(t),"launcher.json")}function tt(t){return P.join(D(t),"bin","crewx-launcher.cmd")}function et(t){return P.join(t,"CrewX.lnk")}function A(t,e){return P.normalize(t).toLowerCase()===P.normalize(e).toLowerCase()}var Xt="[Console]::OutputEncoding = [System.Text.Encoding]::UTF8; [Environment]::GetFolderPath('DesktopDirectory')";async function nt(t){try{let n=await t.run("powershell",["-NoProfile","-NonInteractive","-Command",Xt],{env:t.env}),r=n.stdout.trim();if(n.code===0&&r)return {dir:r,source:"known-folder"}}catch{}let e=t.env.USERPROFILE||t.env.Userprofile||t.homedir();return e?{dir:P.join(e,"Desktop"),source:"fallback"}:null}function W(t,e){let n=P.resolve(e,"node_modules",".bin").toLowerCase();return t.split(";").filter(r=>r?P.resolve(r).toLowerCase()!==n:true).join(";")}function rt(t){return t?/\\Program Files( \(x86\))?\\/i.test(t)&&/crewx/i.test(t):false}function Ht(t,e){let n=a=>{let[l,...h]=a.split("-"),m=h.join("-")||void 0;return {parts:(l??"").split(".").map(p=>Number.parseInt(p,10)||0),pre:m}},r=n(t),s=n(e),c=Math.max(r.parts.length,s.parts.length);for(let a=0;a<c;a++){let l=r.parts[a]??0,h=s.parts[a]??0;if(l!==h)return l<h?-1:1}if(r.pre===s.pre)return 0;if(!r.pre&&s.pre)return 1;if(r.pre&&!s.pre)return -1;let o=Number.parseInt(r.pre.match(/(\d+)$/)?.[1]??"",10),i=Number.parseInt(s.pre.match(/(\d+)$/)?.[1]??"",10);return !Number.isNaN(o)&&!Number.isNaN(i)&&o!==i?o<i?-1:1:r.pre<s.pre?-1:r.pre>s.pre?1:0}function y(t,e){return Ht(t,e)<0}var st=d.win32,it=1;function at(t,e){if(!t.existsSync(e))return null;try{let n=JSON.parse(t.readFileSync(e));return {schema:n.schema??it,shortcutPath:n.shortcutPath,version:n.version,owned:!!n.owned,declined:!!n.declined,desktopSource:n.desktopSource,updatedAt:n.updatedAt}}catch{return null}}function N(t,e,n){let r={schema:it,...n,updatedAt:new Date().toISOString()};t.mkdirSync(st.dirname(e)),t.writeFileSync(e,JSON.stringify(r,null,2));}function _(t,e){if(!t.existsSync(e))return null;try{let n=JSON.parse(t.readFileSync(e));return {schema:n.schema??0,binPath:n.binPath,updatedAt:n.updatedAt}}catch{return null}}function ct(t,e,n){t.mkdirSync(st.dirname(e)),t.writeFileSync(e,JSON.stringify(n,null,2));}var Gt=d.win32,x=1;function Ut(t){return t.replace(/%/g,"%%")}function jt(t){return ["@echo off","setlocal DisableDelayedExpansion","chcp 65001 >nul","",'set "CREWX_WORKDIR=%USERPROFILE%\\crewx"','if not exist "%CREWX_WORKDIR%" mkdir "%CREWX_WORKDIR%" >nul 2>nul','cd /d "%CREWX_WORKDIR%"',"",'set "CREWX_PORT_EFFECTIVE=%CREWX_PORT%"','if "%CREWX_PORT_EFFECTIVE%"=="" set "CREWX_PORT_EFFECTIVE=8150"','set "CREWX_HEALTH_URL=http://127.0.0.1:%CREWX_PORT_EFFECTIVE%/api/v1/health"','set "CREWX_ORIGIN_URL=http://127.0.0.1:%CREWX_PORT_EFFECTIVE%/"',"",t.bakedBinPath?`set "CREWX_FALLBACK_BIN=${Ut(t.bakedBinPath)}"`:'set "CREWX_FALLBACK_BIN="','set "CREWX_RESOLVED_BIN=%CREWX_BIN%"','if "%CREWX_RESOLVED_BIN%"=="" set "CREWX_RESOLVED_BIN=%CREWX_FALLBACK_BIN%"','if "%CREWX_RESOLVED_BIN%"=="" (',` for /f "delims=" %%I in ('where crewx 2^>nul') do (`,' if not defined CREWX_RESOLVED_BIN set "CREWX_RESOLVED_BIN=%%I"'," )",")","",'powershell -NoProfile -NonInteractive -Command "try { $r = Invoke-WebRequest -Uri $env:CREWX_HEALTH_URL -TimeoutSec 1 -UseBasicParsing; if ($r.StatusCode -eq 200) { exit 0 } else { exit 1 } } catch { exit 1 }"',"if %ERRORLEVEL% EQU 0 (",' start "" "%CREWX_ORIGIN_URL%"'," exit /b 0",")","",'if "%CREWX_RESOLVED_BIN%"=="" ('," echo CrewX executable not found. Please reinstall the desktop shortcut."," pause"," exit /b 1",")","",'start "CrewX" /min "%CREWX_RESOLVED_BIN%"',""].join(`\r
|
|
2
|
+
`)}function ut(t){let e=_(t.fs,t.launcherManifestPath),n=!!e&&e.schema>=x&&t.fs.existsSync(t.wrapperPath),r=n&&!e.binPath&&!!t.bakedBinPath;if(n&&!r)return {wrapperPath:t.wrapperPath,wrote:false,schema:e.schema};let c=jt({bakedBinPath:t.bakedBinPath});try{t.fs.mkdirSync(Gt.dirname(t.wrapperPath)),t.fs.writeFileSync(t.wrapperPath,c),ct(t.fs,t.launcherManifestPath,{schema:x,binPath:t.bakedBinPath,updatedAt:new Date().toISOString()});}catch(o){throw o instanceof f?o:new f("WRITE_DENIED",`Could not write launcher wrapper: ${o instanceof Error?o.message:String(o)}`)}return {wrapperPath:t.wrapperPath,wrote:true,schema:x}}var Jt=["$ws = New-Object -ComObject WScript.Shell","$sc = $ws.CreateShortcut($env:CREWX_LNK_PATH)","$sc.TargetPath = $env:CREWX_LNK_TARGET","if ($env:CREWX_LNK_WORKDIR) { $sc.WorkingDirectory = $env:CREWX_LNK_WORKDIR }","$sc.WindowStyle = 7","if ($env:CREWX_LNK_ICON) { $sc.IconLocation = $env:CREWX_LNK_ICON }","$sc.Save()"].join("; "),Kt=["[Console]::OutputEncoding = [System.Text.Encoding]::UTF8","$ws = New-Object -ComObject WScript.Shell","$sc = $ws.CreateShortcut($env:CREWX_LNK_PATH)","[PSCustomObject]@{ TargetPath = $sc.TargetPath; WorkingDirectory = $sc.WorkingDirectory; IconLocation = $sc.IconLocation } | ConvertTo-Json -Compress"].join("; ");async function dt(t){let e={...t.env,CREWX_LNK_PATH:t.shortcutPath,CREWX_LNK_TARGET:t.targetPath,CREWX_LNK_WORKDIR:t.workingDirectory??"",CREWX_LNK_ICON:t.iconPath??""},n;try{n=await t.run("powershell",["-NoProfile","-NonInteractive","-Command",Jt],{env:e});}catch(r){throw new f("POWERSHELL_UNAVAILABLE",`Could not run PowerShell: ${r instanceof Error?r.message:String(r)}`)}if(n.code!==0)throw new f("POWERSHELL_UNAVAILABLE",`Failed to create desktop shortcut: ${n.stderr||n.stdout}`)}function pt(t){let e=t.trim(),n=e.lastIndexOf(",");return n!==-1&&/^-?\d+$/.test(e.slice(n+1).trim())&&(e=e.slice(0,n).trim()),e.length>=2&&e.startsWith('"')&&e.endsWith('"')&&(e=e.slice(1,-1).trim()),e}async function ft(t){try{let e={...t.env,CREWX_LNK_PATH:t.shortcutPath},n=await t.run("powershell",["-NoProfile","-NonInteractive","-Command",Kt],{env:e});if(n.code!==0||!n.stdout.trim())return null;let r=JSON.parse(n.stdout.trim());return {targetPath:r.TargetPath??"",workingDirectory:r.WorkingDirectory??"",iconLocation:r.IconLocation??""}}catch{return null}}var M=d.win32;async function C(t){let e=W(t.env.PATH??t.env.Path??"",t.cwd),n={...t.env,PATH:e,Path:e},r;try{r=await t.run("npm",["list","-g","crewx","--depth=0","--json"],{env:n});}catch{return {installed:false}}let s;try{s=JSON.parse(r.stdout||"{}");}catch{return {installed:false}}let c=s.dependencies?.crewx;if(!c?.version)return {installed:false};let o;try{let a=await t.run("npm",["prefix","-g"],{env:n});a.code===0&&(o=a.stdout.trim()||void 0);}catch{}let i=o?M.join(o,"crewx.cmd"):void 0;return {installed:true,version:c.version,binPath:i,prefix:o}}var zt=/EACCES|EPERM|EROFS/,qt=/ENOTFOUND|ETIMEDOUT|ECONNREFUSED|network|registry/i,Qt=/^\d+\.\d+\.\d+/;function Yt(t){return !!t&&t!=="0.0.0"&&Qt.test(t)}var T=10*6e4;async function mt(t){if(!Yt(t.targetVersion))throw new f("GLOBAL_INSTALL_FAILED",`RUNNING_VERSION_UNKNOWN: cannot reliably determine the running crewx version to install (got ${JSON.stringify(t.targetVersion)}); refusing to fall back to crewx@latest`);if(t.currentInfo?.installed&&t.currentInfo.version&&!y(t.currentInfo.version,t.targetVersion))return {info:t.currentInfo};let e=W(t.env.PATH??t.env.Path??"",t.cwd),n={...t.env,PATH:e,Path:e},r=`crewx@${t.targetVersion}`;t.onProgress?.({phase:"global-install",message:`Installing crewx globally (npm install -g ${r})`});let s;try{s=await t.run("npm",["install","-g",r,"--no-audit","--no-fund"],{env:n,timeoutMs:T});}catch(o){throw new f("NPM_UNAVAILABLE",`Could not run npm: ${o instanceof Error?o.message:String(o)}`)}if(s.code===0)return {info:await C({env:n,cwd:t.cwd,run:t.run})};let c=`${s.stdout}
|
|
3
|
+
${s.stderr}`;if(zt.test(c)){t.onProgress?.({phase:"global-install",message:"Permission denied \u2014 retrying with a user-scoped npm prefix"});let o=t.env.LOCALAPPDATA||M.join(t.env.USERPROFILE??"","AppData","Local"),i={...n,npm_config_prefix:M.join(o,"crewx","npm")},a;try{a=await t.run("npm",["install","-g",r,"--no-audit","--no-fund"],{env:i,timeoutMs:T});}catch(l){throw new f("NPM_PERMISSION_DENIED",`Retry with user-scoped prefix failed: ${l instanceof Error?l.message:String(l)}`)}if(a.code===0)return {info:await C({env:i,cwd:t.cwd,run:t.run})};throw new f("NPM_PERMISSION_DENIED",`npm install -g failed after user-scoped prefix retry: ${a.stderr||a.stdout}`)}if(qt.test(c)){if(!t.installRoot)throw new f("OFFLINE_NO_SOURCE","The npm registry is unreachable and no local installRoot was provided for an offline install");t.onProgress?.({phase:"global-install",message:`Registry unreachable \u2014 installing offline from ${t.installRoot}`});let o;try{o=await t.run("npm",["install","-g",t.installRoot,"--offline","--no-audit","--no-fund"],{env:n,timeoutMs:T});}catch(i){throw new f("GLOBAL_INSTALL_FAILED",`Offline install failed: ${i instanceof Error?i.message:String(i)}`)}if(o.code===0)return {info:await C({env:n,cwd:t.cwd,run:t.run})};throw new f("GLOBAL_INSTALL_FAILED",`Offline install failed: ${o.stderr||o.stdout}`)}throw new f("GLOBAL_INSTALL_FAILED",c.trim()||`npm install -g ${r} failed`)}function Zt(t){return t.run??K}function te(t){return t.fs??V}async function O(t){let e=t.platform??process.platform,n=t.env??process.env,r=t.homedir??B,s=Zt(t),c=te(t),o=t.runningVersion??q,i=t.cwd??process.cwd(),a=r(),l=Y(a),h=Z(a),m=tt(a),u=null;e==="win32"&&(u=await nt({env:n,homedir:r,run:s}));let p=u?et(u.dir):null;return {platform:e,env:n,homedir:r,run:s,fs:c,runningVersion:o,cwd:i,installRoot:t.installRoot,shortcutManifestPath:l,launcherManifestPath:h,wrapperPath:m,desktop:u,shortcutPath:p}}function ee(t){return t?d.win32.normalize(t).toLowerCase().endsWith(`${d.win32.sep}bin${d.win32.sep}crewx.ico`):false}async function E(t){if(t.platform!=="win32")return {supported:false,state:"unsupported",globalCrewx:null,runningVersion:t.runningVersion,errors:[],manifest:null,iconStale:false};let e=[];t.desktop||e.push("NO_DESKTOP_DIR: could not resolve the Windows Desktop directory");let n=at(t.fs,t.shortcutManifestPath),r=_(t.fs,t.launcherManifestPath),s=await C({env:t.env,cwd:t.cwd,run:t.run}),c=t.shortcutPath?t.fs.existsSync(t.shortcutPath):false,o,i=false;if(!c)o=n?.declined?"declined":"not-installed";else {let a=!!n?.owned&&!!t.shortcutPath&&n.shortcutPath===t.shortcutPath,l=false,h=t.shortcutPath?await ft({run:t.run,env:t.env,shortcutPath:t.shortcutPath}):null;if(a||(h&&A(h.targetPath,t.wrapperPath)?a=true:h&&rt(h.targetPath)&&(l=true)),l)o="foreign",e.push("NSIS_PRESENT: an NSIS-installed CrewX shortcut was detected");else if(!a)o="foreign";else if(n?.version&&y(t.runningVersion,n.version))o="superseded",e.push(`SUPERSEDED: running version ${t.runningVersion} is older than the installed shortcut's version ${n.version}; refusing to modify it`);else {let m=!r||r.schema<x||!t.fs.existsSync(t.wrapperPath);if(h){let u=pt(h.iconLocation);if(!(!!u&&t.fs.existsSync(u)))i=true;else {let g=gt(s,t.fs);g?i=!A(u,g):i=!ee(u);}}o=m||i?"stale":"installed";}}return {supported:true,state:o,shortcutPath:t.shortcutPath??void 0,desktopDir:t.desktop?.dir,desktopSource:t.desktop?.source,wrapperPath:t.wrapperPath,wrapperSchema:r?.schema,globalCrewx:s.installed?s:{installed:false},runningVersion:t.runningVersion,errors:e,manifest:n,iconStale:i}}function gt(t,e){if(!t?.installed||!t.prefix)return;let n=d.win32.join(t.prefix,"node_modules","crewx","bin","crewx.ico");return e.existsSync(n)?n:void 0}function R(t){let{manifest:e,iconStale:n,...r}=t;return r}async function ne(t={}){let e=await O(t),n=await E(e);return R(n)}async function re(t={}){let e=await O(t);t.onProgress?.({phase:"detect",message:"Checking current shortcut status"});let n=await E(e),r=R(n);if(!r.supported)return {...r,changed:false,installedGlobal:false};if(r.state==="superseded")return {...r,changed:false,installedGlobal:false};if(r.state==="foreign"){if(n.errors.some(g=>g.startsWith("NSIS_PRESENT")))throw new f("NSIS_PRESENT",`An NSIS-installed CrewX shortcut was detected at ${r.shortcutPath}`);if(!t.force)throw new f("FOREIGN_SHORTCUT",`An existing shortcut at ${r.shortcutPath} is not managed by CrewX`)}if(!e.desktop||!e.shortcutPath)throw new f("NO_DESKTOP_DIR","Could not resolve the Windows Desktop directory");let s=false,c=false,o=r.globalCrewx,i=[];if(!!o?.installed&&!!o.version&&y(o.version,e.runningVersion)||!o?.installed&&r.state!=="installed"){let g=await mt({env:e.env,cwd:e.cwd,run:e.run,targetVersion:e.runningVersion,currentInfo:o??void 0,installRoot:e.installRoot,onProgress:t.onProgress});o=g.info,c=g.info.installed,s=true,c||i.push(`GLOBAL_INSTALL_UNCONFIRMED: npm install -g crewx@${e.runningVersion} exited successfully but a follow-up check could not confirm the global install`);}if(t.onProgress?.({phase:"wrapper",message:"Ensuring launcher wrapper"}),ut({fs:e.fs,wrapperPath:e.wrapperPath,launcherManifestPath:e.launcherManifestPath,bakedBinPath:o?.binPath}).wrote&&(s=true),!((r.state==="installed"||r.state==="stale")&&!n.iconStale)){let g=gt(o,e.fs);if(n.iconStale&&!g)throw new f("ICON_UNAVAILABLE",`Could not locate the global CrewX icon (bin\\crewx.ico) to repair the desktop shortcut at ${e.shortcutPath}; the existing shortcut was left untouched`);t.onProgress?.({phase:"lnk",message:"Creating desktop shortcut"}),await dt({run:e.run,env:e.env,shortcutPath:e.shortcutPath,targetPath:e.wrapperPath,iconPath:g}),s=true;}s&&N(e.fs,e.shortcutManifestPath,{shortcutPath:e.shortcutPath,version:e.runningVersion,owned:true,declined:false,desktopSource:e.desktop.source});let u=await E(e),p=R(u);return {...p,errors:[...p.errors,...i],changed:s,installedGlobal:c}}async function oe(t={}){let e=await O(t),n=await E(e),r=R(n);if(!r.supported)return r;if((r.state==="installed"||r.state==="stale")&&e.shortcutPath)try{e.fs.unlinkSync(e.shortcutPath);}catch{}N(e.fs,e.shortcutManifestPath,{shortcutPath:void 0,version:n.manifest?.version,owned:false,declined:true,desktopSource:void 0});let s=await E(e);return R(s)}async function se(t={}){let e=await O(t),n=await E(e),r=R(n);if(!r.supported)return r;N(e.fs,e.shortcutManifestPath,{shortcutPath:n.manifest?.shortcutPath,version:n.manifest?.version,owned:n.manifest?.owned??false,declined:true,desktopSource:n.manifest?.desktopSource});let s=await E(e);return R(s)}export{f as ShortcutError,se as dismissShortcutNotice,ne as getShortcutStatus,re as installShortcut,oe as uninstallShortcut};
|