@vibe-cafe/vibe-usage 0.14.4 → 0.14.6
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 +7 -4
- package/package.json +1 -1
- package/src/index.js +20 -1
- package/src/parsers/contract.js +5 -2
- package/src/parsers/cursor.js +649 -91
- package/src/state.js +19 -2
- package/src/sync.js +544 -337
package/src/state.js
CHANGED
|
@@ -52,24 +52,37 @@ function sameIdentity(a, b) {
|
|
|
52
52
|
// `identity` is optional: callers that only read the recorded counts (e.g.
|
|
53
53
|
// `status`) pass nothing and keep the pre-0.11.1 behaviour of taking the file
|
|
54
54
|
// at face value.
|
|
55
|
+
function parserMetaFrom(parsed) {
|
|
56
|
+
const meta = parsed?.parserMeta;
|
|
57
|
+
return meta && typeof meta === 'object' && !Array.isArray(meta) ? meta : {};
|
|
58
|
+
}
|
|
59
|
+
|
|
55
60
|
export function loadState(identity) {
|
|
56
61
|
if (!existsSync(STATE_FILE)) return { buckets: {}, sessions: {} };
|
|
57
62
|
try {
|
|
58
63
|
const parsed = JSON.parse(readFileSync(STATE_FILE, 'utf-8'));
|
|
59
64
|
const buckets = parsed.buckets ?? {};
|
|
60
65
|
const sessions = parsed.sessions ?? {};
|
|
66
|
+
// Local parser diagnostics (currently Cursor's account/newest event).
|
|
67
|
+
// Purely additive; older CLIs ignore it and it never enters an upload.
|
|
68
|
+
const parserMeta = parserMetaFrom(parsed);
|
|
69
|
+
const withMeta = (value) => (Object.keys(parserMeta).length > 0
|
|
70
|
+
? { ...value, parserMeta }
|
|
71
|
+
: value);
|
|
61
72
|
if (!isIdentity(identity) || !isIdentity(parsed.identity)) {
|
|
62
73
|
// No identity recorded — written by a CLI older than 0.11.1. Adopt the
|
|
63
74
|
// entries as-is rather than forcing a re-upload: on upgrade day that
|
|
64
75
|
// would make every installed client re-send its whole history at once.
|
|
65
76
|
// The next saveState() stamps the current identity, so any later re-bind
|
|
66
77
|
// is caught.
|
|
67
|
-
return { buckets, sessions };
|
|
78
|
+
return withMeta({ buckets, sessions });
|
|
68
79
|
}
|
|
69
|
-
if (sameIdentity(parsed.identity, identity)) return { buckets, sessions };
|
|
80
|
+
if (sameIdentity(parsed.identity, identity)) return withMeta({ buckets, sessions });
|
|
70
81
|
// Bound to a different account or server: nothing recorded here was ever
|
|
71
82
|
// uploaded to the current target, so start empty and re-send local history.
|
|
72
83
|
// `identityChanged` is a runtime signal for the caller, never persisted.
|
|
84
|
+
// Parser diagnostics describe the old target's local source, so they are
|
|
85
|
+
// dropped with the old hashes.
|
|
73
86
|
return { buckets: {}, sessions: {}, identityChanged: true };
|
|
74
87
|
} catch {
|
|
75
88
|
// Corrupt/unreadable state must not lose data — treat as empty, which
|
|
@@ -91,6 +104,10 @@ export function saveState(state, identity) {
|
|
|
91
104
|
buckets: state.buckets ?? {},
|
|
92
105
|
sessions: state.sessions ?? {},
|
|
93
106
|
};
|
|
107
|
+
if (state.parserMeta && typeof state.parserMeta === 'object'
|
|
108
|
+
&& Object.keys(state.parserMeta).length > 0) {
|
|
109
|
+
payload.parserMeta = state.parserMeta;
|
|
110
|
+
}
|
|
94
111
|
if (isIdentity(identity)) {
|
|
95
112
|
payload.identity = {
|
|
96
113
|
apiUrl: identity.apiUrl,
|