@wibeco/bridge 0.2.17 → 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-4WIGVKDR.js → chunk-C5GHOVVI.js} +42 -5
- package/dist/{chunk-YLC4TF4F.js → chunk-E44G2C5V.js} +263 -122
- package/dist/cli.js +3 -3
- package/dist/codex-hook.js +2 -2
- package/dist/index.d.ts +8 -1
- package/dist/index.js +3 -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;
|
|
@@ -926,6 +931,31 @@ function presenceStatePath(source, sessionId, cwd = process.cwd()) {
|
|
|
926
931
|
return join(presenceDirectory(), `${key}.json`);
|
|
927
932
|
}
|
|
928
933
|
async function resolveLatestPresenceSession(source, cwd = process.cwd(), maxAgeMs = 5 * 6e4) {
|
|
934
|
+
return (await resolveLatestPresenceState(source, cwd, maxAgeMs))?.sessionId;
|
|
935
|
+
}
|
|
936
|
+
async function resolveLatestPresenceTask(source, cwd = process.cwd(), maxAgeMs = 5 * 6e4) {
|
|
937
|
+
const state = await resolveLatestPresenceState(source, cwd, maxAgeMs);
|
|
938
|
+
if (!state?.sessionId) return void 0;
|
|
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;
|
|
957
|
+
}
|
|
958
|
+
async function resolveLatestPresenceState(source, cwd, maxAgeMs) {
|
|
929
959
|
let names;
|
|
930
960
|
try {
|
|
931
961
|
names = await readdir(presenceDirectory());
|
|
@@ -946,13 +976,10 @@ async function resolveLatestPresenceSession(source, cwd = process.cwd(), maxAgeM
|
|
|
946
976
|
continue;
|
|
947
977
|
}
|
|
948
978
|
if (!latest || state.lastActivityAt > latest.lastActivityAt) {
|
|
949
|
-
latest =
|
|
950
|
-
sessionId: state.sessionId,
|
|
951
|
-
lastActivityAt: state.lastActivityAt
|
|
952
|
-
};
|
|
979
|
+
latest = state;
|
|
953
980
|
}
|
|
954
981
|
}
|
|
955
|
-
return latest
|
|
982
|
+
return latest;
|
|
956
983
|
}
|
|
957
984
|
function presenceDirectory() {
|
|
958
985
|
return process.env.WIBE_PRESENCE_DIR ?? join(homedir(), ".wibe", "presence");
|
|
@@ -981,6 +1008,15 @@ async function readPresenceState(path) {
|
|
|
981
1008
|
taskPaths: Array.isArray(value.taskPaths) ? value.taskPaths.filter(
|
|
982
1009
|
(path2) => typeof path2 === "string"
|
|
983
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,
|
|
984
1020
|
paths: Array.isArray(value.paths) ? value.paths.filter((path2) => typeof path2 === "string") : [],
|
|
985
1021
|
model: typeof value.model === "string" ? canonicalModelName(value.model) : void 0,
|
|
986
1022
|
modelSeconds: canonicalModelSeconds(value.modelSeconds),
|
|
@@ -1559,6 +1595,7 @@ export {
|
|
|
1559
1595
|
runPresenceHeartbeat,
|
|
1560
1596
|
presenceStatePath,
|
|
1561
1597
|
resolveLatestPresenceSession,
|
|
1598
|
+
resolveLatestPresenceTask,
|
|
1562
1599
|
classifyHeadTransition,
|
|
1563
1600
|
isObservedPush,
|
|
1564
1601
|
detectRepository,
|
|
@@ -15,11 +15,11 @@ import {
|
|
|
15
15
|
observeRepositoryTransitions,
|
|
16
16
|
pollDeviceToken,
|
|
17
17
|
requestDeviceAuthorization,
|
|
18
|
-
|
|
18
|
+
resolveLatestPresenceTask,
|
|
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,11 +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
|
|
859
|
-
const sessionId = await resolveLatestPresenceSession(
|
|
860
|
-
projectConfig.adapter,
|
|
861
|
-
cwd
|
|
862
|
-
);
|
|
846
|
+
const taskMetrics = await resolveLatestPresenceTask(adapter, cwd);
|
|
863
847
|
const screenshot = options.screenshot?.trim() ? await uploadProgressScreenshot(
|
|
864
848
|
options.screenshot.trim(),
|
|
865
849
|
screenshotAlt,
|
|
@@ -867,19 +851,19 @@ async function shareProgressCommand(options, cwd = process.cwd()) {
|
|
|
867
851
|
cwd
|
|
868
852
|
) : {};
|
|
869
853
|
const event = createHookEvent({
|
|
870
|
-
source:
|
|
854
|
+
source: adapter,
|
|
871
855
|
kind: "progress.shared",
|
|
872
|
-
...sessionId ? { sessionId } : {},
|
|
856
|
+
...taskMetrics?.sessionId ? { sessionId: taskMetrics.sessionId } : {},
|
|
873
857
|
metadata: {
|
|
874
858
|
summary,
|
|
875
859
|
...title ? { title } : {},
|
|
876
860
|
...options.phase ? { phase: options.phase } : {},
|
|
877
861
|
...options.confidence !== void 0 ? { confidence: options.confidence } : {},
|
|
878
862
|
...screenshot.artifactId ? { artifact_id: screenshot.artifactId } : {},
|
|
879
|
-
...
|
|
880
|
-
paths:
|
|
881
|
-
lines_added:
|
|
882
|
-
lines_deleted:
|
|
863
|
+
...taskMetrics && (taskMetrics.paths.length > 0 || taskMetrics.linesAdded > 0 || taskMetrics.linesDeleted > 0) ? {
|
|
864
|
+
paths: taskMetrics.paths,
|
|
865
|
+
lines_added: taskMetrics.linesAdded,
|
|
866
|
+
lines_deleted: taskMetrics.linesDeleted
|
|
883
867
|
} : {}
|
|
884
868
|
},
|
|
885
869
|
...repo ? { repo } : {}
|
|
@@ -922,24 +906,101 @@ async function doctorCommand(cwd = process.cwd(), requestedRepository) {
|
|
|
922
906
|
const credentialMatchesProjectConfig = Boolean(
|
|
923
907
|
credential && projectConfig && credential.projectId === projectConfig.projectId && credential.appUrl.replace(/\/$/, "") === projectConfig.appUrl.replace(/\/$/, "")
|
|
924
908
|
);
|
|
925
|
-
let
|
|
909
|
+
let adapters = [];
|
|
926
910
|
let adapterError;
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
}
|
|
930
|
-
|
|
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
|
+
}
|
|
931
919
|
}
|
|
932
|
-
const
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
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
|
+
);
|
|
937
958
|
const queueNotes = [
|
|
938
959
|
`note project queue ${queuePath} contains ${queueBacklog ?? "unknown"} event(s)`,
|
|
939
960
|
...legacyQueue.pending ? [
|
|
940
961
|
`note legacy shared queue is quarantined at ${legacyQueue.quarantined} and will not be delivered automatically`
|
|
941
962
|
] : []
|
|
942
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
|
+
];
|
|
943
1004
|
const checks = [
|
|
944
1005
|
["node", Number(process.versions.node.split(".")[0]) >= 20],
|
|
945
1006
|
["git repository", Boolean(repository)],
|
|
@@ -960,25 +1021,8 @@ async function doctorCommand(cwd = process.cwd(), requestedRepository) {
|
|
|
960
1021
|
queueError ? `project queue (${queueError})` : "project queue",
|
|
961
1022
|
queueError === void 0
|
|
962
1023
|
],
|
|
963
|
-
[
|
|
964
|
-
|
|
965
|
-
Boolean(adapter)
|
|
966
|
-
],
|
|
967
|
-
["agent hooks configuration", nativeConfig.hooks],
|
|
968
|
-
["MCP endpoint configuration", nativeConfig.mcp],
|
|
969
|
-
["agent activity instructions", nativeConfig.activityRule],
|
|
970
|
-
...adapter === "codex" ? [
|
|
971
|
-
...nativeConfig.projectTrust === void 0 ? [] : [
|
|
972
|
-
[
|
|
973
|
-
nativeConfig.projectTrust ? "Codex project trust" : "Codex project trust (trust this project in Codex, then review Wibe hooks in /hooks)",
|
|
974
|
-
nativeConfig.projectTrust
|
|
975
|
-
]
|
|
976
|
-
]
|
|
977
|
-
] : [],
|
|
978
|
-
[
|
|
979
|
-
heartbeat?.error ? `verification heartbeat (${heartbeat.error})` : "verification heartbeat",
|
|
980
|
-
Boolean(heartbeat && !heartbeat.error)
|
|
981
|
-
]
|
|
1024
|
+
...adapters.length > 1 ? [["adapter detection", adapters.length > 0]] : [],
|
|
1025
|
+
...adapterChecks
|
|
982
1026
|
];
|
|
983
1027
|
const failures = checks.filter(([, okay]) => !okay).length;
|
|
984
1028
|
return {
|
|
@@ -990,7 +1034,8 @@ async function doctorCommand(cwd = process.cwd(), requestedRepository) {
|
|
|
990
1034
|
].join("\n")
|
|
991
1035
|
};
|
|
992
1036
|
}
|
|
993
|
-
async function loadCredential(cwd) {
|
|
1037
|
+
async function loadCredential(cwd, adapter, options = {}) {
|
|
1038
|
+
const fallbackToPrimary = options.fallbackToPrimary !== false;
|
|
994
1039
|
if (process.env.WIBE_ACCESS_TOKEN && process.env.WIBE_PROJECT_ID && process.env.WIBE_ORGANIZATION_ID && process.env.WIBE_DEVICE_ID) {
|
|
995
1040
|
const credential = {
|
|
996
1041
|
appUrl: process.env.WIBE_APP_URL ?? "http://localhost:3000",
|
|
@@ -1004,18 +1049,31 @@ async function loadCredential(cwd) {
|
|
|
1004
1049
|
if (!project || project.projectId !== credential.projectId || project.appUrl.replace(/\/$/, "") !== credential.appUrl.replace(/\/$/, "")) {
|
|
1005
1050
|
return null;
|
|
1006
1051
|
}
|
|
1052
|
+
if (adapter && adapter !== project.adapter && !fallbackToPrimary) {
|
|
1053
|
+
return null;
|
|
1054
|
+
}
|
|
1007
1055
|
return credential;
|
|
1008
1056
|
}
|
|
1009
1057
|
try {
|
|
1010
1058
|
const project = await readProjectConfig(join(cwd, ".wibe", "project.json"));
|
|
1011
1059
|
if (!project) return null;
|
|
1012
|
-
const
|
|
1013
|
-
|
|
1014
|
-
project.projectId
|
|
1060
|
+
const requested = adapter ?? project.adapter;
|
|
1061
|
+
const accounts = credentialAccounts(
|
|
1062
|
+
project.projectId,
|
|
1063
|
+
requested,
|
|
1064
|
+
project.adapter,
|
|
1065
|
+
fallbackToPrimary
|
|
1015
1066
|
);
|
|
1016
|
-
|
|
1017
|
-
const
|
|
1018
|
-
|
|
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;
|
|
1019
1077
|
} catch {
|
|
1020
1078
|
return null;
|
|
1021
1079
|
}
|
|
@@ -1370,24 +1428,44 @@ var REPOSITORY_SIGNALS = {
|
|
|
1370
1428
|
};
|
|
1371
1429
|
async function detectAdapter(explicitAdapter, cwd = process.cwd(), environment = process.env) {
|
|
1372
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
|
+
}
|
|
1373
1447
|
const configuredProject = await readProjectConfig(join(cwd, ".wibe", "project.json"));
|
|
1374
|
-
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
|
+
}
|
|
1375
1455
|
const candidates = /* @__PURE__ */ new Map();
|
|
1376
1456
|
for (const adapter of ADAPTERS) {
|
|
1377
|
-
const environmentMatches = ENVIRONMENT_SIGNALS[adapter].filter(
|
|
1378
|
-
(name) => typeof environment[name] === "string" && environment[name] !== ""
|
|
1379
|
-
);
|
|
1380
1457
|
const repositoryMatches = (await Promise.all(
|
|
1381
1458
|
REPOSITORY_SIGNALS[adapter].map(async (path) => ({
|
|
1382
1459
|
path,
|
|
1383
1460
|
found: await exists(join(cwd, path))
|
|
1384
1461
|
}))
|
|
1385
1462
|
)).filter(({ found }) => found).map(({ path }) => path);
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1463
|
+
if (repositoryMatches.length > 0) {
|
|
1464
|
+
candidates.set(
|
|
1465
|
+
adapter,
|
|
1466
|
+
repositoryMatches.map((path) => `config ${path}`)
|
|
1467
|
+
);
|
|
1468
|
+
}
|
|
1391
1469
|
}
|
|
1392
1470
|
if (candidates.size === 1) return candidates.keys().next().value;
|
|
1393
1471
|
if (candidates.size === 0) {
|
|
@@ -1400,6 +1478,61 @@ async function detectAdapter(explicitAdapter, cwd = process.cwd(), environment =
|
|
|
1400
1478
|
`Adapter detection is ambiguous: ${details}. Pass --adapter <${ADAPTERS.join("|")}> to choose explicitly.`
|
|
1401
1479
|
);
|
|
1402
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
|
+
}
|
|
1403
1536
|
async function readProjectConfig(path) {
|
|
1404
1537
|
if (!await exists(path)) return void 0;
|
|
1405
1538
|
let parsed;
|
|
@@ -1419,6 +1552,14 @@ async function readProjectConfig(path) {
|
|
|
1419
1552
|
if (parsed.repository) {
|
|
1420
1553
|
parsed.repository = normalizeGitHubRepository(parsed.repository);
|
|
1421
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
|
+
}
|
|
1422
1563
|
return parsed;
|
|
1423
1564
|
}
|
|
1424
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.d.ts
CHANGED
|
@@ -311,12 +311,19 @@ interface PresenceMetrics {
|
|
|
311
311
|
tests_failed: number;
|
|
312
312
|
last_activity_at: string;
|
|
313
313
|
}
|
|
314
|
+
interface PresenceTaskMetrics {
|
|
315
|
+
sessionId: string;
|
|
316
|
+
linesAdded: number;
|
|
317
|
+
linesDeleted: number;
|
|
318
|
+
paths: string[];
|
|
319
|
+
}
|
|
314
320
|
declare function startPresenceSession(source: AgentSource, sessionId: string | undefined, cwd?: string): Promise<PresenceMetrics>;
|
|
315
321
|
declare function updatePresenceSession(source: AgentSource, sessionId: string | undefined, event: CanonicalHookEvent, cwd?: string): Promise<PresenceMetrics | undefined>;
|
|
316
322
|
declare function stopPresenceSession(source: AgentSource, sessionId: string | undefined, cwd?: string): Promise<PresenceMetrics | undefined>;
|
|
317
323
|
declare function runPresenceHeartbeat(statePath: string, expectedInstanceId: string, emit: (source: AgentSource, eventName: string, payload: Record<string, unknown>) => Promise<unknown>, intervalMs?: number): Promise<void>;
|
|
318
324
|
declare function presenceStatePath(source: AgentSource, sessionId: string | undefined, cwd?: string): string;
|
|
319
325
|
declare function resolveLatestPresenceSession(source: AgentSource, cwd?: string, maxAgeMs?: number): Promise<string | undefined>;
|
|
326
|
+
declare function resolveLatestPresenceTask(source: AgentSource, cwd?: string, maxAgeMs?: number): Promise<PresenceTaskMetrics | undefined>;
|
|
320
327
|
|
|
321
328
|
interface RedactionOptions {
|
|
322
329
|
allowContent?: boolean;
|
|
@@ -358,4 +365,4 @@ declare function sanitizeRemote(remote: string): string;
|
|
|
358
365
|
declare function normalizeGitHubRepository(value: string): string | undefined;
|
|
359
366
|
declare function matchesGitHubRepository(remote: string | undefined, expected: string): boolean;
|
|
360
367
|
|
|
361
|
-
export { type AgentSource, type CanonicalHookEvent, type CredentialStore, type DeviceAuthorization, type DeviceTokenResponse, type FlushResult, type HookEventKind, JsonFileOfflineQueue, MemoryOfflineQueue, type OfflineQueue, type OfflineQueueTransaction, PRESENCE_HEARTBEAT_INTERVAL_MS, type PresenceMetrics, type RedactionOptions, type RepositoryInfo, type RepositoryTransition, type SafeValue, SignedBatchClient, type SignedBatchClientOptions, type StoredCredential, SystemCredentialStore, type WorkingTreeMetrics, agentSourceSchema, canonicalHookEventSchema, classifyHeadTransition, createHookEvent, detectRepository, detectWorkingTreeMetrics, deviceAuthorizationSchema, deviceTokenResponseSchema, eventTypeForHook, hookEventKindSchema, isObservedPush, mapClaudeCodeHook, mapCodexHook, mapCursorHook, matchesGitHubRepository, normalizeGitHubRepository, observeRepositoryTransitions, pollDeviceToken, presenceStatePath, redact, requestDeviceAuthorization, resolveLatestPresenceSession, runPresenceHeartbeat, safeMetadata, safeValueSchema, sanitizeRemote, startPresenceSession, stopPresenceSession, updatePresenceSession };
|
|
368
|
+
export { type AgentSource, type CanonicalHookEvent, type CredentialStore, type DeviceAuthorization, type DeviceTokenResponse, type FlushResult, type HookEventKind, JsonFileOfflineQueue, MemoryOfflineQueue, type OfflineQueue, type OfflineQueueTransaction, PRESENCE_HEARTBEAT_INTERVAL_MS, type PresenceMetrics, type PresenceTaskMetrics, type RedactionOptions, type RepositoryInfo, type RepositoryTransition, type SafeValue, SignedBatchClient, type SignedBatchClientOptions, type StoredCredential, SystemCredentialStore, type WorkingTreeMetrics, agentSourceSchema, canonicalHookEventSchema, classifyHeadTransition, createHookEvent, detectRepository, detectWorkingTreeMetrics, deviceAuthorizationSchema, deviceTokenResponseSchema, eventTypeForHook, hookEventKindSchema, isObservedPush, mapClaudeCodeHook, mapCodexHook, mapCursorHook, matchesGitHubRepository, normalizeGitHubRepository, observeRepositoryTransitions, pollDeviceToken, presenceStatePath, redact, requestDeviceAuthorization, resolveLatestPresenceSession, resolveLatestPresenceTask, runPresenceHeartbeat, safeMetadata, safeValueSchema, sanitizeRemote, startPresenceSession, stopPresenceSession, updatePresenceSession };
|
package/dist/index.js
CHANGED
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
redact,
|
|
27
27
|
requestDeviceAuthorization,
|
|
28
28
|
resolveLatestPresenceSession,
|
|
29
|
+
resolveLatestPresenceTask,
|
|
29
30
|
runPresenceHeartbeat,
|
|
30
31
|
safeMetadata,
|
|
31
32
|
safeValueSchema,
|
|
@@ -33,7 +34,7 @@ import {
|
|
|
33
34
|
startPresenceSession,
|
|
34
35
|
stopPresenceSession,
|
|
35
36
|
updatePresenceSession
|
|
36
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-C5GHOVVI.js";
|
|
37
38
|
export {
|
|
38
39
|
JsonFileOfflineQueue,
|
|
39
40
|
MemoryOfflineQueue,
|
|
@@ -62,6 +63,7 @@ export {
|
|
|
62
63
|
redact,
|
|
63
64
|
requestDeviceAuthorization,
|
|
64
65
|
resolveLatestPresenceSession,
|
|
66
|
+
resolveLatestPresenceTask,
|
|
65
67
|
runPresenceHeartbeat,
|
|
66
68
|
safeMetadata,
|
|
67
69
|
safeValueSchema,
|
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`,
|
|
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`,
|
|
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`,
|
|
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.
|