@wibeco/bridge 0.2.18 → 0.2.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-HP5FH4VQ.js → chunk-C5GHOVVI.js} +32 -6
- package/dist/{chunk-UWS3QC3N.js → chunk-E44G2C5V.js} +257 -115
- package/dist/cli.js +3 -3
- package/dist/codex-hook.js +2 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/templates/claude-code/wibe-activity.md.example +1 -1
- package/templates/codex/wibe-activity.md.example +1 -1
- package/templates/cursor/wibe-activity.mdc.example +1 -1
|
@@ -879,6 +879,11 @@ async function updatePresenceSession(source, sessionId, event, cwd = process.cwd
|
|
|
879
879
|
}
|
|
880
880
|
const metrics = metricsFromState(state, measuredAt);
|
|
881
881
|
if (event.kind === "lifecycle.after") {
|
|
882
|
+
if (state.taskLinesAdded > 0 || state.taskLinesDeleted > 0 || state.taskPaths.length > 0) {
|
|
883
|
+
state.lastCompletedTaskLinesAdded = state.taskLinesAdded;
|
|
884
|
+
state.lastCompletedTaskLinesDeleted = state.taskLinesDeleted;
|
|
885
|
+
state.lastCompletedTaskPaths = state.taskPaths;
|
|
886
|
+
}
|
|
882
887
|
state.taskBaselineLinesAdded = workingLinesAdded;
|
|
883
888
|
state.taskBaselineLinesDeleted = workingLinesDeleted;
|
|
884
889
|
state.taskLinesAdded = 0;
|
|
@@ -931,12 +936,24 @@ async function resolveLatestPresenceSession(source, cwd = process.cwd(), maxAgeM
|
|
|
931
936
|
async function resolveLatestPresenceTask(source, cwd = process.cwd(), maxAgeMs = 5 * 6e4) {
|
|
932
937
|
const state = await resolveLatestPresenceState(source, cwd, maxAgeMs);
|
|
933
938
|
if (!state?.sessionId) return void 0;
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
939
|
+
const liveHasMetrics = state.taskLinesAdded > 0 || state.taskLinesDeleted > 0 || state.taskPaths.length > 0;
|
|
940
|
+
if (liveHasMetrics) {
|
|
941
|
+
return {
|
|
942
|
+
sessionId: state.sessionId,
|
|
943
|
+
linesAdded: state.taskLinesAdded,
|
|
944
|
+
linesDeleted: state.taskLinesDeleted,
|
|
945
|
+
paths: state.taskPaths
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
if ((state.lastCompletedTaskLinesAdded ?? 0) > 0 || (state.lastCompletedTaskLinesDeleted ?? 0) > 0 || (state.lastCompletedTaskPaths?.length ?? 0) > 0) {
|
|
949
|
+
return {
|
|
950
|
+
sessionId: state.sessionId,
|
|
951
|
+
linesAdded: state.lastCompletedTaskLinesAdded ?? 0,
|
|
952
|
+
linesDeleted: state.lastCompletedTaskLinesDeleted ?? 0,
|
|
953
|
+
paths: state.lastCompletedTaskPaths ?? []
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
return void 0;
|
|
940
957
|
}
|
|
941
958
|
async function resolveLatestPresenceState(source, cwd, maxAgeMs) {
|
|
942
959
|
let names;
|
|
@@ -991,6 +1008,15 @@ async function readPresenceState(path) {
|
|
|
991
1008
|
taskPaths: Array.isArray(value.taskPaths) ? value.taskPaths.filter(
|
|
992
1009
|
(path2) => typeof path2 === "string"
|
|
993
1010
|
) : [],
|
|
1011
|
+
lastCompletedTaskLinesAdded: optionalCount(
|
|
1012
|
+
value.lastCompletedTaskLinesAdded
|
|
1013
|
+
),
|
|
1014
|
+
lastCompletedTaskLinesDeleted: optionalCount(
|
|
1015
|
+
value.lastCompletedTaskLinesDeleted
|
|
1016
|
+
),
|
|
1017
|
+
lastCompletedTaskPaths: Array.isArray(value.lastCompletedTaskPaths) ? value.lastCompletedTaskPaths.filter(
|
|
1018
|
+
(path2) => typeof path2 === "string"
|
|
1019
|
+
) : void 0,
|
|
994
1020
|
paths: Array.isArray(value.paths) ? value.paths.filter((path2) => typeof path2 === "string") : [],
|
|
995
1021
|
model: typeof value.model === "string" ? canonicalModelName(value.model) : void 0,
|
|
996
1022
|
modelSeconds: canonicalModelSeconds(value.modelSeconds),
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
startPresenceSession,
|
|
20
20
|
stopPresenceSession,
|
|
21
21
|
updatePresenceSession
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-C5GHOVVI.js";
|
|
23
23
|
|
|
24
24
|
// src/cli/commands.ts
|
|
25
25
|
import { createHash } from "crypto";
|
|
@@ -302,12 +302,18 @@ async function setupCommand(requestedAdapter, options = {}) {
|
|
|
302
302
|
}
|
|
303
303
|
const projectConfigPath = join(cwd, ".wibe", "project.json");
|
|
304
304
|
const existingProjectConfig = await readProjectConfig(projectConfigPath);
|
|
305
|
-
if (existingProjectConfig
|
|
306
|
-
|
|
307
|
-
|
|
305
|
+
if (existingProjectConfig) {
|
|
306
|
+
assertCompatibleProjectConfig(
|
|
307
|
+
existingProjectConfig,
|
|
308
|
+
{
|
|
309
|
+
projectId: options.projectId,
|
|
310
|
+
appUrl,
|
|
311
|
+
repository: expectedRepository
|
|
312
|
+
},
|
|
313
|
+
projectConfigPath
|
|
308
314
|
);
|
|
309
315
|
}
|
|
310
|
-
const existingCredential = existingProjectConfig ? await loadCredential(cwd) : null;
|
|
316
|
+
const existingCredential = existingProjectConfig ? await loadCredential(cwd, adapter, { fallbackToPrimary: false }) : null;
|
|
311
317
|
if (!options.reauthorize && existingCredential && existingCredential.projectId === options.projectId && existingCredential.appUrl.replace(/\/$/, "") === appUrl) {
|
|
312
318
|
const installedNativeFiles2 = await installNativeConfigs(
|
|
313
319
|
adapter,
|
|
@@ -317,6 +323,12 @@ async function setupCommand(requestedAdapter, options = {}) {
|
|
|
317
323
|
options.projectId
|
|
318
324
|
);
|
|
319
325
|
await adoptPendingQueue(cwd, options.projectId);
|
|
326
|
+
await writeProjectConfigFile(projectConfigPath, existingProjectConfig, {
|
|
327
|
+
projectId: options.projectId,
|
|
328
|
+
appUrl,
|
|
329
|
+
adapter,
|
|
330
|
+
repository: expectedRepository ?? existingProjectConfig?.repository
|
|
331
|
+
});
|
|
320
332
|
const heartbeat2 = await sendVerificationHeartbeat(
|
|
321
333
|
existingCredential,
|
|
322
334
|
adapter,
|
|
@@ -367,40 +379,17 @@ Confirm code ${authorization.user_code}
|
|
|
367
379
|
repositoryId: token.repositoryId,
|
|
368
380
|
deviceId: token.deviceId
|
|
369
381
|
};
|
|
370
|
-
await
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
382
|
+
await storeCredential(
|
|
383
|
+
credential,
|
|
384
|
+
adapter,
|
|
385
|
+
existingProjectConfig?.adapter ?? adapter
|
|
374
386
|
);
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
projectId: token.projectId,
|
|
382
|
-
appUrl,
|
|
383
|
-
adapter,
|
|
384
|
-
...expectedRepository ? { repository: expectedRepository } : {}
|
|
385
|
-
},
|
|
386
|
-
null,
|
|
387
|
-
2
|
|
388
|
-
)}
|
|
389
|
-
`,
|
|
390
|
-
{ mode: 384, flag: "wx" }
|
|
391
|
-
);
|
|
392
|
-
} else if (expectedRepository && !existingProjectConfig.repository) {
|
|
393
|
-
await writeFile(
|
|
394
|
-
projectConfigPath,
|
|
395
|
-
`${JSON.stringify(
|
|
396
|
-
{ ...existingProjectConfig, repository: expectedRepository },
|
|
397
|
-
null,
|
|
398
|
-
2
|
|
399
|
-
)}
|
|
400
|
-
`,
|
|
401
|
-
{ mode: 384 }
|
|
402
|
-
);
|
|
403
|
-
}
|
|
387
|
+
await writeProjectConfigFile(projectConfigPath, existingProjectConfig, {
|
|
388
|
+
projectId: token.projectId,
|
|
389
|
+
appUrl,
|
|
390
|
+
adapter,
|
|
391
|
+
repository: expectedRepository ?? existingProjectConfig?.repository
|
|
392
|
+
});
|
|
404
393
|
const installedNativeFiles = await installNativeConfigs(
|
|
405
394
|
adapter,
|
|
406
395
|
source,
|
|
@@ -546,8 +535,18 @@ Install the Wibe GitHub App on ${repository}, then return here.
|
|
|
546
535
|
}
|
|
547
536
|
const projectConfigPath = join(cwd, ".wibe", "project.json");
|
|
548
537
|
const existingProjectConfig = await readProjectConfig(projectConfigPath);
|
|
549
|
-
|
|
550
|
-
|
|
538
|
+
if (existingProjectConfig) {
|
|
539
|
+
assertCompatibleProjectConfig(
|
|
540
|
+
existingProjectConfig,
|
|
541
|
+
{
|
|
542
|
+
projectId: snapshot.project_id,
|
|
543
|
+
appUrl,
|
|
544
|
+
repository
|
|
545
|
+
},
|
|
546
|
+
projectConfigPath
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
let credential = existingProjectConfig ? await loadCredential(cwd, adapter, { fallbackToPrimary: false }) : null;
|
|
551
550
|
if (!credential || credential.projectId !== snapshot.project_id || credential.appUrl.replace(/\/$/, "") !== appUrl) {
|
|
552
551
|
const minted = await mintOnboardingDevice({
|
|
553
552
|
appUrl,
|
|
@@ -563,30 +562,18 @@ Install the Wibe GitHub App on ${repository}, then return here.
|
|
|
563
562
|
repositoryId: minted.repositoryId,
|
|
564
563
|
deviceId: minted.deviceId
|
|
565
564
|
};
|
|
566
|
-
await
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
565
|
+
await storeCredential(
|
|
566
|
+
credential,
|
|
567
|
+
adapter,
|
|
568
|
+
existingProjectConfig?.adapter ?? adapter
|
|
570
569
|
);
|
|
571
|
-
if (!existingProjectConfig) {
|
|
572
|
-
await mkdir(join(cwd, ".wibe"), { recursive: true });
|
|
573
|
-
await writeFile(
|
|
574
|
-
projectConfigPath,
|
|
575
|
-
`${JSON.stringify(
|
|
576
|
-
{
|
|
577
|
-
projectId: minted.projectId,
|
|
578
|
-
appUrl,
|
|
579
|
-
adapter,
|
|
580
|
-
repository
|
|
581
|
-
},
|
|
582
|
-
null,
|
|
583
|
-
2
|
|
584
|
-
)}
|
|
585
|
-
`,
|
|
586
|
-
{ mode: 384, flag: "wx" }
|
|
587
|
-
);
|
|
588
|
-
}
|
|
589
570
|
}
|
|
571
|
+
await writeProjectConfigFile(projectConfigPath, existingProjectConfig, {
|
|
572
|
+
projectId: snapshot.project_id,
|
|
573
|
+
appUrl,
|
|
574
|
+
adapter,
|
|
575
|
+
repository
|
|
576
|
+
});
|
|
590
577
|
const installedNativeFiles = await installNativeConfigs(
|
|
591
578
|
adapter,
|
|
592
579
|
source,
|
|
@@ -784,7 +771,7 @@ async function emitCommand(adapter, eventName, input) {
|
|
|
784
771
|
const publishableEvents = [event, ...repositoryEvents].filter(
|
|
785
772
|
(candidate) => eventTypeForHook(candidate)
|
|
786
773
|
);
|
|
787
|
-
const credential = await loadCredential(process.cwd());
|
|
774
|
+
const credential = await loadCredential(process.cwd(), adapter);
|
|
788
775
|
await quarantineLegacyQueue();
|
|
789
776
|
const queue = new JsonFileOfflineQueue(
|
|
790
777
|
credential ? projectQueuePath(credential.projectId) : pendingQueuePath(repo?.root ?? process.cwd())
|
|
@@ -823,8 +810,9 @@ async function shareProgressCommand(options, cwd = process.cwd()) {
|
|
|
823
810
|
const projectConfig = await readProjectConfig(
|
|
824
811
|
join(cwd, ".wibe", "project.json")
|
|
825
812
|
);
|
|
826
|
-
const
|
|
827
|
-
|
|
813
|
+
const adapter = projectConfig ? await detectAdapter(void 0, cwd).catch(() => projectConfig.adapter) : void 0;
|
|
814
|
+
const credential = await loadCredential(cwd, adapter);
|
|
815
|
+
if (!projectConfig || !credential || !adapter) {
|
|
828
816
|
throw new Error("Wibe is not authorized in this repository. Run wibe setup first.");
|
|
829
817
|
}
|
|
830
818
|
await quarantineLegacyQueue();
|
|
@@ -855,10 +843,7 @@ async function shareProgressCommand(options, cwd = process.cwd()) {
|
|
|
855
843
|
throw new Error("Progress confidence must be between 0 and 1.");
|
|
856
844
|
}
|
|
857
845
|
const repo = await detectRepository(cwd);
|
|
858
|
-
const taskMetrics = await resolveLatestPresenceTask(
|
|
859
|
-
projectConfig.adapter,
|
|
860
|
-
cwd
|
|
861
|
-
);
|
|
846
|
+
const taskMetrics = await resolveLatestPresenceTask(adapter, cwd);
|
|
862
847
|
const screenshot = options.screenshot?.trim() ? await uploadProgressScreenshot(
|
|
863
848
|
options.screenshot.trim(),
|
|
864
849
|
screenshotAlt,
|
|
@@ -866,7 +851,7 @@ async function shareProgressCommand(options, cwd = process.cwd()) {
|
|
|
866
851
|
cwd
|
|
867
852
|
) : {};
|
|
868
853
|
const event = createHookEvent({
|
|
869
|
-
source:
|
|
854
|
+
source: adapter,
|
|
870
855
|
kind: "progress.shared",
|
|
871
856
|
...taskMetrics?.sessionId ? { sessionId: taskMetrics.sessionId } : {},
|
|
872
857
|
metadata: {
|
|
@@ -921,24 +906,101 @@ async function doctorCommand(cwd = process.cwd(), requestedRepository) {
|
|
|
921
906
|
const credentialMatchesProjectConfig = Boolean(
|
|
922
907
|
credential && projectConfig && credential.projectId === projectConfig.projectId && credential.appUrl.replace(/\/$/, "") === projectConfig.appUrl.replace(/\/$/, "")
|
|
923
908
|
);
|
|
924
|
-
let
|
|
909
|
+
let adapters = [];
|
|
925
910
|
let adapterError;
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
}
|
|
929
|
-
|
|
911
|
+
if (projectConfig) {
|
|
912
|
+
adapters = configuredAdapters(projectConfig);
|
|
913
|
+
} else {
|
|
914
|
+
try {
|
|
915
|
+
adapters = [await detectAdapter(void 0, cwd)];
|
|
916
|
+
} catch (error) {
|
|
917
|
+
adapterError = error instanceof Error ? error.message : String(error);
|
|
918
|
+
}
|
|
930
919
|
}
|
|
931
|
-
const
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
920
|
+
const nativeByAdapter = await Promise.all(
|
|
921
|
+
adapters.map(async (adapter) => ({
|
|
922
|
+
adapter,
|
|
923
|
+
native: await validateNativeConfigs(adapter, cwd, projectConfig?.projectId),
|
|
924
|
+
credential: await loadCredential(cwd, adapter, {
|
|
925
|
+
fallbackToPrimary: adapters.length <= 1
|
|
926
|
+
})
|
|
927
|
+
}))
|
|
928
|
+
);
|
|
929
|
+
const primaryAdapter = adapters[0];
|
|
930
|
+
const primaryNative = nativeByAdapter[0]?.native ?? {
|
|
931
|
+
hooks: false,
|
|
932
|
+
mcp: false,
|
|
933
|
+
activityRule: false,
|
|
934
|
+
projectTrust: void 0
|
|
935
|
+
};
|
|
936
|
+
const heartbeatResults = await Promise.all(
|
|
937
|
+
nativeByAdapter.map(async ({ adapter, credential: adapterCredential }) => {
|
|
938
|
+
if (!adapterCredential || !repositoryMatches || !credentialMatchesProjectConfig) {
|
|
939
|
+
return { adapter, heartbeat: void 0 };
|
|
940
|
+
}
|
|
941
|
+
return {
|
|
942
|
+
adapter,
|
|
943
|
+
heartbeat: await sendVerificationHeartbeat(
|
|
944
|
+
adapterCredential,
|
|
945
|
+
adapter,
|
|
946
|
+
"doctor",
|
|
947
|
+
cwd
|
|
948
|
+
)
|
|
949
|
+
};
|
|
950
|
+
})
|
|
951
|
+
);
|
|
952
|
+
const primaryHeartbeat = heartbeatResults[0]?.heartbeat;
|
|
953
|
+
const trustNotes = nativeByAdapter.flatMap(
|
|
954
|
+
({ adapter, native }) => adapter === "codex" && native.projectTrust === void 0 ? [
|
|
955
|
+
"note Codex project trust could not be verified because the user config was not found; trust this project in Codex and rerun doctor"
|
|
956
|
+
] : []
|
|
957
|
+
);
|
|
936
958
|
const queueNotes = [
|
|
937
959
|
`note project queue ${queuePath} contains ${queueBacklog ?? "unknown"} event(s)`,
|
|
938
960
|
...legacyQueue.pending ? [
|
|
939
961
|
`note legacy shared queue is quarantined at ${legacyQueue.quarantined} and will not be delivered automatically`
|
|
940
962
|
] : []
|
|
941
963
|
];
|
|
964
|
+
const adapterChecks = adapters.length > 1 ? nativeByAdapter.flatMap(({ adapter, native, credential: adapterCredential }) => {
|
|
965
|
+
const heartbeat = heartbeatResults.find(
|
|
966
|
+
(item) => item.adapter === adapter
|
|
967
|
+
)?.heartbeat;
|
|
968
|
+
return [
|
|
969
|
+
[`${adapter} agent hooks configuration`, native.hooks],
|
|
970
|
+
[`${adapter} MCP endpoint configuration`, native.mcp],
|
|
971
|
+
[`${adapter} agent activity instructions`, native.activityRule],
|
|
972
|
+
...adapter === "codex" ? native.projectTrust === void 0 ? [] : [
|
|
973
|
+
[
|
|
974
|
+
native.projectTrust ? `${adapter} Codex project trust` : `${adapter} Codex project trust (trust this project in Codex, then review Wibe hooks in /hooks)`,
|
|
975
|
+
native.projectTrust
|
|
976
|
+
]
|
|
977
|
+
] : [],
|
|
978
|
+
[
|
|
979
|
+
heartbeat?.error ? `${adapter} verification heartbeat (${heartbeat.error})` : `${adapter} verification heartbeat`,
|
|
980
|
+
Boolean(adapterCredential && heartbeat && !heartbeat.error)
|
|
981
|
+
]
|
|
982
|
+
];
|
|
983
|
+
}) : [
|
|
984
|
+
[
|
|
985
|
+
adapterError ? `adapter detection (${adapterError})` : "adapter detection",
|
|
986
|
+
Boolean(primaryAdapter)
|
|
987
|
+
],
|
|
988
|
+
["agent hooks configuration", primaryNative.hooks],
|
|
989
|
+
["MCP endpoint configuration", primaryNative.mcp],
|
|
990
|
+
["agent activity instructions", primaryNative.activityRule],
|
|
991
|
+
...primaryAdapter === "codex" ? [
|
|
992
|
+
...primaryNative.projectTrust === void 0 ? [] : [
|
|
993
|
+
[
|
|
994
|
+
primaryNative.projectTrust ? "Codex project trust" : "Codex project trust (trust this project in Codex, then review Wibe hooks in /hooks)",
|
|
995
|
+
primaryNative.projectTrust
|
|
996
|
+
]
|
|
997
|
+
]
|
|
998
|
+
] : [],
|
|
999
|
+
[
|
|
1000
|
+
primaryHeartbeat?.error ? `verification heartbeat (${primaryHeartbeat.error})` : "verification heartbeat",
|
|
1001
|
+
Boolean(primaryHeartbeat && !primaryHeartbeat.error)
|
|
1002
|
+
]
|
|
1003
|
+
];
|
|
942
1004
|
const checks = [
|
|
943
1005
|
["node", Number(process.versions.node.split(".")[0]) >= 20],
|
|
944
1006
|
["git repository", Boolean(repository)],
|
|
@@ -959,25 +1021,8 @@ async function doctorCommand(cwd = process.cwd(), requestedRepository) {
|
|
|
959
1021
|
queueError ? `project queue (${queueError})` : "project queue",
|
|
960
1022
|
queueError === void 0
|
|
961
1023
|
],
|
|
962
|
-
[
|
|
963
|
-
|
|
964
|
-
Boolean(adapter)
|
|
965
|
-
],
|
|
966
|
-
["agent hooks configuration", nativeConfig.hooks],
|
|
967
|
-
["MCP endpoint configuration", nativeConfig.mcp],
|
|
968
|
-
["agent activity instructions", nativeConfig.activityRule],
|
|
969
|
-
...adapter === "codex" ? [
|
|
970
|
-
...nativeConfig.projectTrust === void 0 ? [] : [
|
|
971
|
-
[
|
|
972
|
-
nativeConfig.projectTrust ? "Codex project trust" : "Codex project trust (trust this project in Codex, then review Wibe hooks in /hooks)",
|
|
973
|
-
nativeConfig.projectTrust
|
|
974
|
-
]
|
|
975
|
-
]
|
|
976
|
-
] : [],
|
|
977
|
-
[
|
|
978
|
-
heartbeat?.error ? `verification heartbeat (${heartbeat.error})` : "verification heartbeat",
|
|
979
|
-
Boolean(heartbeat && !heartbeat.error)
|
|
980
|
-
]
|
|
1024
|
+
...adapters.length > 1 ? [["adapter detection", adapters.length > 0]] : [],
|
|
1025
|
+
...adapterChecks
|
|
981
1026
|
];
|
|
982
1027
|
const failures = checks.filter(([, okay]) => !okay).length;
|
|
983
1028
|
return {
|
|
@@ -989,7 +1034,8 @@ async function doctorCommand(cwd = process.cwd(), requestedRepository) {
|
|
|
989
1034
|
].join("\n")
|
|
990
1035
|
};
|
|
991
1036
|
}
|
|
992
|
-
async function loadCredential(cwd) {
|
|
1037
|
+
async function loadCredential(cwd, adapter, options = {}) {
|
|
1038
|
+
const fallbackToPrimary = options.fallbackToPrimary !== false;
|
|
993
1039
|
if (process.env.WIBE_ACCESS_TOKEN && process.env.WIBE_PROJECT_ID && process.env.WIBE_ORGANIZATION_ID && process.env.WIBE_DEVICE_ID) {
|
|
994
1040
|
const credential = {
|
|
995
1041
|
appUrl: process.env.WIBE_APP_URL ?? "http://localhost:3000",
|
|
@@ -1003,18 +1049,31 @@ async function loadCredential(cwd) {
|
|
|
1003
1049
|
if (!project || project.projectId !== credential.projectId || project.appUrl.replace(/\/$/, "") !== credential.appUrl.replace(/\/$/, "")) {
|
|
1004
1050
|
return null;
|
|
1005
1051
|
}
|
|
1052
|
+
if (adapter && adapter !== project.adapter && !fallbackToPrimary) {
|
|
1053
|
+
return null;
|
|
1054
|
+
}
|
|
1006
1055
|
return credential;
|
|
1007
1056
|
}
|
|
1008
1057
|
try {
|
|
1009
1058
|
const project = await readProjectConfig(join(cwd, ".wibe", "project.json"));
|
|
1010
1059
|
if (!project) return null;
|
|
1011
|
-
const
|
|
1012
|
-
|
|
1013
|
-
project.projectId
|
|
1060
|
+
const requested = adapter ?? project.adapter;
|
|
1061
|
+
const accounts = credentialAccounts(
|
|
1062
|
+
project.projectId,
|
|
1063
|
+
requested,
|
|
1064
|
+
project.adapter,
|
|
1065
|
+
fallbackToPrimary
|
|
1014
1066
|
);
|
|
1015
|
-
|
|
1016
|
-
const
|
|
1017
|
-
|
|
1067
|
+
const store = new SystemCredentialStore();
|
|
1068
|
+
for (const account of accounts) {
|
|
1069
|
+
const stored = await store.get("dev.wibe.bridge", account);
|
|
1070
|
+
if (!stored) continue;
|
|
1071
|
+
const credential = JSON.parse(stored);
|
|
1072
|
+
if (credential.projectId === project.projectId && credential.appUrl.replace(/\/$/, "") === project.appUrl.replace(/\/$/, "")) {
|
|
1073
|
+
return credential;
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
return null;
|
|
1018
1077
|
} catch {
|
|
1019
1078
|
return null;
|
|
1020
1079
|
}
|
|
@@ -1369,24 +1428,44 @@ var REPOSITORY_SIGNALS = {
|
|
|
1369
1428
|
};
|
|
1370
1429
|
async function detectAdapter(explicitAdapter, cwd = process.cwd(), environment = process.env) {
|
|
1371
1430
|
if (explicitAdapter) return explicitAdapter;
|
|
1431
|
+
const environmentAdapters = ADAPTERS.filter(
|
|
1432
|
+
(adapter) => ENVIRONMENT_SIGNALS[adapter].some(
|
|
1433
|
+
(name) => typeof environment[name] === "string" && environment[name] !== ""
|
|
1434
|
+
)
|
|
1435
|
+
);
|
|
1436
|
+
if (environmentAdapters.length === 1) return environmentAdapters[0];
|
|
1437
|
+
if (environmentAdapters.length > 1) {
|
|
1438
|
+
const details2 = environmentAdapters.map(
|
|
1439
|
+
(adapter) => `${adapter} (${ENVIRONMENT_SIGNALS[adapter].filter(
|
|
1440
|
+
(name) => typeof environment[name] === "string" && environment[name] !== ""
|
|
1441
|
+
).map((name) => `environment ${name}`).join(", ")})`
|
|
1442
|
+
).join("; ");
|
|
1443
|
+
throw new Error(
|
|
1444
|
+
`Adapter detection is ambiguous: ${details2}. Pass --adapter <${ADAPTERS.join("|")}> to choose explicitly.`
|
|
1445
|
+
);
|
|
1446
|
+
}
|
|
1372
1447
|
const configuredProject = await readProjectConfig(join(cwd, ".wibe", "project.json"));
|
|
1373
|
-
if (configuredProject)
|
|
1448
|
+
if (configuredProject) {
|
|
1449
|
+
const adapters = configuredAdapters(configuredProject);
|
|
1450
|
+
if (adapters.length === 1) return adapters[0];
|
|
1451
|
+
throw new Error(
|
|
1452
|
+
`Adapter detection is ambiguous: ${adapters.join(", ")}. Pass --adapter <${ADAPTERS.join("|")}> to choose explicitly.`
|
|
1453
|
+
);
|
|
1454
|
+
}
|
|
1374
1455
|
const candidates = /* @__PURE__ */ new Map();
|
|
1375
1456
|
for (const adapter of ADAPTERS) {
|
|
1376
|
-
const environmentMatches = ENVIRONMENT_SIGNALS[adapter].filter(
|
|
1377
|
-
(name) => typeof environment[name] === "string" && environment[name] !== ""
|
|
1378
|
-
);
|
|
1379
1457
|
const repositoryMatches = (await Promise.all(
|
|
1380
1458
|
REPOSITORY_SIGNALS[adapter].map(async (path) => ({
|
|
1381
1459
|
path,
|
|
1382
1460
|
found: await exists(join(cwd, path))
|
|
1383
1461
|
}))
|
|
1384
1462
|
)).filter(({ found }) => found).map(({ path }) => path);
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1463
|
+
if (repositoryMatches.length > 0) {
|
|
1464
|
+
candidates.set(
|
|
1465
|
+
adapter,
|
|
1466
|
+
repositoryMatches.map((path) => `config ${path}`)
|
|
1467
|
+
);
|
|
1468
|
+
}
|
|
1390
1469
|
}
|
|
1391
1470
|
if (candidates.size === 1) return candidates.keys().next().value;
|
|
1392
1471
|
if (candidates.size === 0) {
|
|
@@ -1399,6 +1478,61 @@ async function detectAdapter(explicitAdapter, cwd = process.cwd(), environment =
|
|
|
1399
1478
|
`Adapter detection is ambiguous: ${details}. Pass --adapter <${ADAPTERS.join("|")}> to choose explicitly.`
|
|
1400
1479
|
);
|
|
1401
1480
|
}
|
|
1481
|
+
function configuredAdapters(project) {
|
|
1482
|
+
const listed = (project.adapters ?? []).filter(
|
|
1483
|
+
(adapter) => ADAPTERS.includes(adapter)
|
|
1484
|
+
);
|
|
1485
|
+
return [.../* @__PURE__ */ new Set([project.adapter, ...listed])];
|
|
1486
|
+
}
|
|
1487
|
+
function credentialAccount(projectId, adapter, primaryAdapter) {
|
|
1488
|
+
return adapter === primaryAdapter ? projectId : `${projectId}:${adapter}`;
|
|
1489
|
+
}
|
|
1490
|
+
function credentialAccounts(projectId, adapter, primaryAdapter, fallbackToPrimary) {
|
|
1491
|
+
const preferred = credentialAccount(projectId, adapter, primaryAdapter);
|
|
1492
|
+
if (!fallbackToPrimary || preferred === projectId) {
|
|
1493
|
+
return preferred === projectId ? [projectId, `${projectId}:${adapter}`] : [preferred];
|
|
1494
|
+
}
|
|
1495
|
+
return [.../* @__PURE__ */ new Set([preferred, projectId])];
|
|
1496
|
+
}
|
|
1497
|
+
async function storeCredential(credential, adapter, primaryAdapter) {
|
|
1498
|
+
await new SystemCredentialStore().set(
|
|
1499
|
+
"dev.wibe.bridge",
|
|
1500
|
+
credentialAccount(credential.projectId, adapter, primaryAdapter),
|
|
1501
|
+
JSON.stringify(credential)
|
|
1502
|
+
);
|
|
1503
|
+
}
|
|
1504
|
+
function projectConfigWithAdapter(existing, input) {
|
|
1505
|
+
const adapters = [
|
|
1506
|
+
.../* @__PURE__ */ new Set([
|
|
1507
|
+
...existing ? configuredAdapters(existing) : [],
|
|
1508
|
+
input.adapter
|
|
1509
|
+
])
|
|
1510
|
+
];
|
|
1511
|
+
return {
|
|
1512
|
+
projectId: input.projectId,
|
|
1513
|
+
appUrl: input.appUrl,
|
|
1514
|
+
adapter: existing?.adapter ?? input.adapter,
|
|
1515
|
+
adapters,
|
|
1516
|
+
...input.repository ? { repository: input.repository } : {}
|
|
1517
|
+
};
|
|
1518
|
+
}
|
|
1519
|
+
function assertCompatibleProjectConfig(existing, incoming, projectConfigPath) {
|
|
1520
|
+
if (existing.projectId !== incoming.projectId || existing.appUrl.replace(/\/$/, "") !== incoming.appUrl.replace(/\/$/, "") || existing.repository && incoming.repository && existing.repository !== incoming.repository) {
|
|
1521
|
+
throw new Error(
|
|
1522
|
+
`Existing ${projectConfigPath} targets a different project, URL, or repository. It was not overwritten; remove it intentionally or rerun setup with matching options.`
|
|
1523
|
+
);
|
|
1524
|
+
}
|
|
1525
|
+
}
|
|
1526
|
+
async function writeProjectConfigFile(projectConfigPath, existing, input) {
|
|
1527
|
+
const next = projectConfigWithAdapter(existing, input);
|
|
1528
|
+
await mkdir(resolve(projectConfigPath, ".."), { recursive: true });
|
|
1529
|
+
await writeFile(
|
|
1530
|
+
projectConfigPath,
|
|
1531
|
+
`${JSON.stringify(next, null, 2)}
|
|
1532
|
+
`,
|
|
1533
|
+
{ mode: 384, ...existing ? {} : { flag: "wx" } }
|
|
1534
|
+
);
|
|
1535
|
+
}
|
|
1402
1536
|
async function readProjectConfig(path) {
|
|
1403
1537
|
if (!await exists(path)) return void 0;
|
|
1404
1538
|
let parsed;
|
|
@@ -1418,6 +1552,14 @@ async function readProjectConfig(path) {
|
|
|
1418
1552
|
if (parsed.repository) {
|
|
1419
1553
|
parsed.repository = normalizeGitHubRepository(parsed.repository);
|
|
1420
1554
|
}
|
|
1555
|
+
if (Array.isArray(parsed.adapters)) {
|
|
1556
|
+
parsed.adapters = parsed.adapters.filter(
|
|
1557
|
+
(adapter) => ADAPTERS.includes(adapter)
|
|
1558
|
+
);
|
|
1559
|
+
if (!parsed.adapters.length) delete parsed.adapters;
|
|
1560
|
+
} else {
|
|
1561
|
+
delete parsed.adapters;
|
|
1562
|
+
}
|
|
1421
1563
|
return parsed;
|
|
1422
1564
|
}
|
|
1423
1565
|
async function assertExpectedRepository(cwd, expected) {
|
package/dist/cli.js
CHANGED
|
@@ -7,10 +7,10 @@ import {
|
|
|
7
7
|
setupCommand,
|
|
8
8
|
shareProgressCommand,
|
|
9
9
|
statusCommand
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-E44G2C5V.js";
|
|
11
11
|
import {
|
|
12
12
|
runPresenceHeartbeat
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-C5GHOVVI.js";
|
|
14
14
|
|
|
15
15
|
// src/cli.ts
|
|
16
16
|
var HELP = `wibe-bridge <command>
|
|
@@ -21,7 +21,7 @@ Commands:
|
|
|
21
21
|
Prints browser URLs for GitHub sign-in and GitHub App install.
|
|
22
22
|
setup --project <uuid> [--adapter <cursor|claude-code|codex>] [--url <wibe-url>] [--repository <owner/repo>] [--reauthorize]
|
|
23
23
|
Auto-detects one adapter from the environment or repository config.
|
|
24
|
-
|
|
24
|
+
Run again with --adapter to connect an additional coding agent to the same project.
|
|
25
25
|
Use --reauthorize only to replace a rejected or revoked device token.
|
|
26
26
|
status
|
|
27
27
|
emit --adapter <name> --event <hook-name> (JSON payload on stdin)
|
package/dist/codex-hook.js
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
- For text-only outcomes, use `wibe_share_progress` with phase `shipped` at completion. Publish earlier only with phase `blocked` when a material blocker leaves the task unfinished.
|
|
9
9
|
- Write one self-contained paragraph of 20–55 words in past tense. Lead with what now works, then explain the user or team impact and meaningful validation. Mention important limitations when present.
|
|
10
10
|
- Describe the outcome, not the agent’s process. Never include first-person narration, prompts, source code, secrets, raw commands, routine tool calls, filenames, line counts, praise, hype, or speculation; Wibe displays code and file changes separately.
|
|
11
|
-
- When calling `wibe_share_progress`, pass `paths`, `lines_added`, and `lines_deleted` only for the current user task. Use the agent's per-task edit results; never pass the repository's full uncommitted diff. If exact task metrics are unavailable, omit them so Wibe can use hook-derived metrics instead of guessed totals.
|
|
11
|
+
- When calling `wibe_share_progress`, pass `session_id` when this conversation or thread has an identifier so the update attaches to this agent session rather than another agent on the same project. Pass `paths`, `lines_added`, and `lines_deleted` only for the current user task. Use the agent's per-task edit results; never pass the repository's full uncommitted diff. If exact task metrics are unavailable, omit them so Wibe can use hook-derived metrics instead of guessed totals.
|
|
12
12
|
- This instruction is standing user authorization to publish the single completion update described here; do not ask for separate per-task approval.
|
|
13
13
|
- If the MCP tool is unavailable, run `npx --yes --package @wibeco/bridge@latest wibe share-progress --summary "<summary>" --phase <shipped|blocked>`.
|
|
14
14
|
- Do not silently skip reporting. If both mechanisms fail, state `Wibe: update failed` and the reason in the final response. Report a Wibe update as sent only after the tool or CLI confirms success.
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
- For text-only outcomes, use `wibe_share_progress` with phase `shipped` at completion. Publish earlier only with phase `blocked` when a material blocker leaves the task unfinished.
|
|
9
9
|
- Write one self-contained paragraph of 20–55 words in past tense. Lead with what now works, then explain the user or team impact and meaningful validation. Mention important limitations when present.
|
|
10
10
|
- Describe the outcome, not the agent’s process. Never include first-person narration, prompts, source code, secrets, raw commands, routine tool calls, filenames, line counts, praise, hype, or speculation; Wibe displays code and file changes separately.
|
|
11
|
-
- When calling `wibe_share_progress`, pass `paths`, `lines_added`, and `lines_deleted` only for the current user task. Use the agent's per-task edit results; never pass the repository's full uncommitted diff. If exact task metrics are unavailable, omit them so Wibe can use hook-derived metrics instead of guessed totals.
|
|
11
|
+
- When calling `wibe_share_progress`, pass `session_id` when this conversation or thread has an identifier so the update attaches to this agent session rather than another agent on the same project. Pass `paths`, `lines_added`, and `lines_deleted` only for the current user task. Use the agent's per-task edit results; never pass the repository's full uncommitted diff. If exact task metrics are unavailable, omit them so Wibe can use hook-derived metrics instead of guessed totals.
|
|
12
12
|
- This instruction is standing user authorization to publish the single completion update described here; do not ask for separate per-task approval.
|
|
13
13
|
- If the MCP tool is unavailable, run `npx --yes --package @wibeco/bridge@latest wibe share-progress --summary "<summary>" --phase <shipped|blocked>`.
|
|
14
14
|
- Do not silently skip reporting. If both mechanisms fail, state `Wibe: update failed` and the reason in the final response. Report a Wibe update as sent only after the tool or CLI confirms success.
|
|
@@ -12,7 +12,7 @@ alwaysApply: true
|
|
|
12
12
|
- For text-only outcomes, use `wibe_share_progress` with phase `shipped` at completion. Publish earlier only with phase `blocked` when a material blocker leaves the task unfinished.
|
|
13
13
|
- Write one self-contained paragraph of 20–55 words in past tense. Lead with what now works, then explain the user or team impact and meaningful validation. Mention important limitations when present.
|
|
14
14
|
- Describe the outcome, not the agent’s process. Never include first-person narration, prompts, source code, secrets, raw commands, routine tool calls, filenames, line counts, praise, hype, or speculation; Wibe displays code and file changes separately.
|
|
15
|
-
- When calling `wibe_share_progress`, pass `paths`, `lines_added`, and `lines_deleted` only for the current user task. Use the agent's per-task edit results; never pass the repository's full uncommitted diff. If exact task metrics are unavailable, omit them so Wibe can use hook-derived metrics instead of guessed totals.
|
|
15
|
+
- When calling `wibe_share_progress`, pass `session_id` when this conversation or thread has an identifier so the update attaches to this agent session rather than another agent on the same project. Pass `paths`, `lines_added`, and `lines_deleted` only for the current user task. Use the agent's per-task edit results; never pass the repository's full uncommitted diff. If exact task metrics are unavailable, omit them so Wibe can use hook-derived metrics instead of guessed totals.
|
|
16
16
|
- Bias frontend outcomes toward visual evidence without asking for per-task approval. For UI components, pages, styling, responsive behavior, interactions, and visual fixes, attach one screenshot when the app or preview is already runnable. Prefer a screenshot already made during visual QA; otherwise capture the clearest final state.
|
|
17
17
|
- Frame screenshots around the feature, not the whole application. Use the browser snapshot to identify the smallest element that contains the changed component and the context needed to understand it, then call `browser_take_screenshot` with that element’s `ref` and a descriptive `element` name. Include the trigger with an open menu, popover, or dialog when practical. Use viewport or full-page screenshots only for page-wide work, and reject captures dominated by blank space.
|
|
18
18
|
- Skip screenshots for backend, infrastructure, documentation, refactors, and non-visual frontend logic. Never launch or repair an app solely for Wibe, and omit the image when navigation needs manual authentication, the state contains sensitive data, visual validation is blocked, or the project has visual updates disabled.
|