@cydm/happy-elves 0.1.0-beta.502 → 0.1.0-beta.503
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
CHANGED
|
@@ -6,8 +6,8 @@ Public beta CLI for Happy Elves.
|
|
|
6
6
|
|
|
7
7
|
Run once in the existing user account; it detects %USERPROFILE%\.happy-elves\hosted, keeps the current daemon and sessions running, installs the independent updater, and registers per-user startup.
|
|
8
8
|
|
|
9
|
-
npm.cmd install --prefix $HOME\.happy-elves\management-entry --ignore-scripts --no-audit --no-fund --package-lock=false @cydm/happy-elves@0.1.0-beta.
|
|
10
|
-
npm.cmd exec --yes --package @cydm/happy-elves@0.1.0-beta.
|
|
9
|
+
npm.cmd install --prefix $HOME\.happy-elves\management-entry --ignore-scripts --no-audit --no-fund --package-lock=false @cydm/happy-elves@0.1.0-beta.503
|
|
10
|
+
npm.cmd exec --yes --package @cydm/happy-elves@0.1.0-beta.503 -- happy-elves-updater install --state-root $HOME\.happy-elves\hosted --autostart
|
|
11
11
|
|
|
12
12
|
The same updater entrypoint works on macOS after selecting a permanent user prefix.
|
|
13
13
|
|
package/apps/cli/package.json
CHANGED
package/apps/daemon/package.json
CHANGED
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cydm/happy-elves",
|
|
3
|
-
"version": "0.1.0-beta.
|
|
3
|
+
"version": "0.1.0-beta.503",
|
|
4
4
|
"description": "Remote controller for local coding agents with hosted or self-hosted relay support.",
|
|
5
|
-
"buildId": "
|
|
5
|
+
"buildId": "0c1a102010e1f13050d123a2ff389e79",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"bin": {
|
|
8
8
|
"happy-elves": "./apps/cli/dist/index.js",
|
|
@@ -575,7 +575,7 @@ export class HeadlessRuntimeCore {
|
|
|
575
575
|
.filter((item) => !mappedItemIds.has(item.id))
|
|
576
576
|
.filter((item) => item.type === "agentMessage" || item.type === "userMessage")
|
|
577
577
|
.filter((item) => mappedSourceItems.some((sourceItem) => (sourceItem.kind === "assistant" ? item.type === "agentMessage" : item.type === "userMessage")
|
|
578
|
-
&& item.text === sourceItem.text))
|
|
578
|
+
&& (item.text === sourceItem.text || nativeUserInputTextEqual(sourceItem, item))))
|
|
579
579
|
.map((item) => item.id);
|
|
580
580
|
if (duplicateTextItemIds.length > 0) {
|
|
581
581
|
removedItemIds.push(...duplicateTextItemIds);
|
|
@@ -3094,6 +3094,21 @@ function runtimeTurnIdForProviderTurn(thread, providerTurnId, providerCheckpoint
|
|
|
3094
3094
|
function nativeItemBindingKey(providerTurnId, providerItemId) {
|
|
3095
3095
|
return `${providerTurnId}\0${providerItemId}`;
|
|
3096
3096
|
}
|
|
3097
|
+
/**
|
|
3098
|
+
* Native providers occasionally append a transport newline to a user input
|
|
3099
|
+
* when reopening a turn. Treat that as the same input only at this mapping
|
|
3100
|
+
* boundary: the comparison is turn-scoped, kind-scoped, and one-to-one. We
|
|
3101
|
+
* intentionally do not trim arbitrary whitespace or apply this to assistant
|
|
3102
|
+
* output, so legitimate repeated prompts remain distinct.
|
|
3103
|
+
*/
|
|
3104
|
+
function nativeUserInputTextEqual(source, projected) {
|
|
3105
|
+
if (source.kind !== "user" || projected.type !== "userMessage" || !("text" in projected))
|
|
3106
|
+
return false;
|
|
3107
|
+
if (projected.text === source.text)
|
|
3108
|
+
return true;
|
|
3109
|
+
const withoutTerminalNewline = (value) => value.replace(/(?:\r\n|\n|\r)+$/g, "");
|
|
3110
|
+
return withoutTerminalNewline(projected.text) === withoutTerminalNewline(source.text);
|
|
3111
|
+
}
|
|
3097
3112
|
/**
|
|
3098
3113
|
* Map provider-native items onto an existing HE turn projection.
|
|
3099
3114
|
*
|
|
@@ -3141,7 +3156,7 @@ function mapNativeItemsToProjection(sourceItems, existingItems, priorBindings, p
|
|
|
3141
3156
|
continue;
|
|
3142
3157
|
}
|
|
3143
3158
|
const sourceItem = sourceItems[sourceIndex];
|
|
3144
|
-
const exact = candidateAtOrAfterCursor((item) => item.type === sourceType(sourceItem) && "text" in item && item.text === sourceItem.text);
|
|
3159
|
+
const exact = candidateAtOrAfterCursor((item) => item.type === sourceType(sourceItem) && "text" in item && (item.text === sourceItem.text || nativeUserInputTextEqual(sourceItem, item)));
|
|
3145
3160
|
if (exact) {
|
|
3146
3161
|
itemIds[sourceIndex] = exact.item.id;
|
|
3147
3162
|
usedExisting.add(exact.item.id);
|
|
@@ -3188,7 +3203,8 @@ function mapNativeItemsToProjection(sourceItems, existingItems, priorBindings, p
|
|
|
3188
3203
|
continue;
|
|
3189
3204
|
}
|
|
3190
3205
|
const mappedText = indexes.map((index) => sourceItems[index].text).join("");
|
|
3191
|
-
|
|
3206
|
+
const singleUserItem = indexes.length === 1 && sourceItems[indexes[0]]?.kind === "user";
|
|
3207
|
+
if (!(singleUserItem ? nativeUserInputTextEqual(sourceItems[indexes[0]], existing) : mappedText === existing.text))
|
|
3192
3208
|
valid = false;
|
|
3193
3209
|
}
|
|
3194
3210
|
const complete = valid
|