olakai-cli 0.9.0 → 0.10.0
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/index.js +205 -17
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2838,9 +2838,194 @@ function registerProfilesCommand(program2) {
|
|
|
2838
2838
|
});
|
|
2839
2839
|
}
|
|
2840
2840
|
|
|
2841
|
+
// src/commands/profile.ts
|
|
2842
|
+
var DIMENSION_ORDER = [
|
|
2843
|
+
{ key: "delegation", label: "Delegation" },
|
|
2844
|
+
{ key: "direction", label: "Direction" },
|
|
2845
|
+
{ key: "verification", label: "Verification" },
|
|
2846
|
+
{ key: "product_judgment", label: "Product Judgment" },
|
|
2847
|
+
{ key: "preparation", label: "Preparation" },
|
|
2848
|
+
{ key: "spend_efficiency", label: "Spend Efficiency" }
|
|
2849
|
+
];
|
|
2850
|
+
function formatDollars(cents) {
|
|
2851
|
+
return `$${(cents / 100).toFixed(2)}`;
|
|
2852
|
+
}
|
|
2853
|
+
function pad(s, width) {
|
|
2854
|
+
return s.length >= width ? s : s + " ".repeat(width - s.length);
|
|
2855
|
+
}
|
|
2856
|
+
function scoreBar(score) {
|
|
2857
|
+
if (score === null) return "\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7\xB7";
|
|
2858
|
+
const filled = Math.min(10, Math.max(0, Math.round(score)));
|
|
2859
|
+
return "\u2588".repeat(filled) + "\u2591".repeat(10 - filled);
|
|
2860
|
+
}
|
|
2861
|
+
async function fetchProfile() {
|
|
2862
|
+
const token = getValidToken();
|
|
2863
|
+
if (!token) {
|
|
2864
|
+
return { data: null, error: "not logged in" };
|
|
2865
|
+
}
|
|
2866
|
+
const controller = new AbortController();
|
|
2867
|
+
const timeout = setTimeout(() => controller.abort(), 8e3);
|
|
2868
|
+
try {
|
|
2869
|
+
const response = await fetch(`${getBaseUrl()}/api/coding-iq/me/profile`, {
|
|
2870
|
+
headers: {
|
|
2871
|
+
Authorization: `Bearer ${token}`
|
|
2872
|
+
},
|
|
2873
|
+
signal: controller.signal
|
|
2874
|
+
});
|
|
2875
|
+
if (response.status === 401) {
|
|
2876
|
+
return { data: null, error: "session expired" };
|
|
2877
|
+
}
|
|
2878
|
+
if (!response.ok) {
|
|
2879
|
+
return { data: null, error: "unreachable" };
|
|
2880
|
+
}
|
|
2881
|
+
const data = await response.json();
|
|
2882
|
+
return { data, error: null };
|
|
2883
|
+
} catch {
|
|
2884
|
+
return { data: null, error: "unreachable" };
|
|
2885
|
+
} finally {
|
|
2886
|
+
clearTimeout(timeout);
|
|
2887
|
+
}
|
|
2888
|
+
}
|
|
2889
|
+
var SECTION_WIDTH = 56;
|
|
2890
|
+
function sectionHeader(title) {
|
|
2891
|
+
const line = `\u2500\u2500 ${title} `;
|
|
2892
|
+
return line + "\u2500".repeat(Math.max(0, SECTION_WIDTH - line.length));
|
|
2893
|
+
}
|
|
2894
|
+
function noProfileMessage(backend, backendError) {
|
|
2895
|
+
if (backendError === "not logged in") {
|
|
2896
|
+
return "Run `olakai login` to see your Builder Profile.";
|
|
2897
|
+
}
|
|
2898
|
+
if (backendError === "session expired") {
|
|
2899
|
+
return "Session expired. Run `olakai login` to refresh your credentials.";
|
|
2900
|
+
}
|
|
2901
|
+
if (backendError === "unreachable") {
|
|
2902
|
+
return "Could not reach Olakai. Your Builder Profile will be here once you're back online.";
|
|
2903
|
+
}
|
|
2904
|
+
if (!backend || !backend.found || !backend.profile) {
|
|
2905
|
+
if (backend?.reason === "opted_out") {
|
|
2906
|
+
return "Your Builder Profile is turned off. Re-enable it from your Olakai settings to start seeing your digest.";
|
|
2907
|
+
}
|
|
2908
|
+
return "Not enough coding sessions yet to build your profile. Keep working with monitoring on \u2014 your Builder Profile appears after your first few sessions are analyzed.";
|
|
2909
|
+
}
|
|
2910
|
+
return null;
|
|
2911
|
+
}
|
|
2912
|
+
function renderHuman(backend, backendError, reportUrl) {
|
|
2913
|
+
const message = noProfileMessage(backend, backendError);
|
|
2914
|
+
if (message) {
|
|
2915
|
+
console.log(message);
|
|
2916
|
+
return;
|
|
2917
|
+
}
|
|
2918
|
+
const profile = backend.profile;
|
|
2919
|
+
console.log(sectionHeader("BUILDER PROFILE"));
|
|
2920
|
+
if (profile.identity.displayName) {
|
|
2921
|
+
console.log(` ${profile.identity.displayName}`);
|
|
2922
|
+
}
|
|
2923
|
+
const dominant = profile.archetype.dominant;
|
|
2924
|
+
if (dominant) {
|
|
2925
|
+
const score = dominant.meanScore !== null ? `${dominant.meanScore.toFixed(1)}/10` : "\u2014";
|
|
2926
|
+
console.log(
|
|
2927
|
+
` ${dominant.archetype} (${score}, ${dominant.evidenceCount} ${dominant.evidenceCount === 1 ? "episode" : "episodes"})`
|
|
2928
|
+
);
|
|
2929
|
+
const secondary = profile.archetype.secondary;
|
|
2930
|
+
if (secondary) {
|
|
2931
|
+
const sScore = secondary.meanScore !== null ? `${secondary.meanScore.toFixed(1)}/10` : "\u2014";
|
|
2932
|
+
console.log(` Secondary: ${secondary.archetype} (${sScore})`);
|
|
2933
|
+
}
|
|
2934
|
+
} else {
|
|
2935
|
+
console.log(" No dominant archetype yet \u2014 not enough evidence.");
|
|
2936
|
+
}
|
|
2937
|
+
if (profile.reducedFidelity) {
|
|
2938
|
+
console.log(" (reduced fidelity \u2014 based on a small number of episodes)");
|
|
2939
|
+
}
|
|
2940
|
+
console.log();
|
|
2941
|
+
console.log(sectionHeader("DIMENSIONS"));
|
|
2942
|
+
for (const { key, label } of DIMENSION_ORDER) {
|
|
2943
|
+
const dim = profile.dimensions[key];
|
|
2944
|
+
if (!dim || dim.meanScore === null || dim.evidenceCount === 0) {
|
|
2945
|
+
console.log(` ${pad(label, 18)} ${scoreBar(null)} no evidence yet`);
|
|
2946
|
+
continue;
|
|
2947
|
+
}
|
|
2948
|
+
console.log(
|
|
2949
|
+
` ${pad(label, 18)} ${scoreBar(dim.meanScore)} ${dim.meanScore.toFixed(1)}/10`
|
|
2950
|
+
);
|
|
2951
|
+
}
|
|
2952
|
+
console.log();
|
|
2953
|
+
const roi = profile.roi;
|
|
2954
|
+
console.log(sectionHeader("PERSONAL ROI (this month)"));
|
|
2955
|
+
if (roi.personalSpendCents !== null) {
|
|
2956
|
+
console.log(` AI spend: ${formatDollars(roi.personalSpendCents)}`);
|
|
2957
|
+
} else {
|
|
2958
|
+
console.log(" AI spend: \u2014");
|
|
2959
|
+
}
|
|
2960
|
+
if (roi.costPerCommitCents !== null) {
|
|
2961
|
+
console.log(
|
|
2962
|
+
` Cost per commit: ${formatDollars(roi.costPerCommitCents)}`
|
|
2963
|
+
);
|
|
2964
|
+
} else {
|
|
2965
|
+
console.log(" Cost per commit: insufficient outcome data");
|
|
2966
|
+
}
|
|
2967
|
+
if (roi.leakedSpendCents !== null && roi.leakedSpendCents > 0) {
|
|
2968
|
+
const efficiencyNote = roi.spendEfficiency?.rationale ? ` (${roi.spendEfficiency.rationale})` : "";
|
|
2969
|
+
console.log(
|
|
2970
|
+
` Top leak: ${formatDollars(roi.leakedSpendCents)} leaked${efficiencyNote}`
|
|
2971
|
+
);
|
|
2972
|
+
} else if (roi.leakedSpendCents === null) {
|
|
2973
|
+
console.log(" Top leak: \u2014");
|
|
2974
|
+
} else {
|
|
2975
|
+
console.log(" Top leak: none detected");
|
|
2976
|
+
}
|
|
2977
|
+
if (roi.roiMultiplier !== null) {
|
|
2978
|
+
console.log(` ROI: ${roi.roiMultiplier.toFixed(1)}x`);
|
|
2979
|
+
} else {
|
|
2980
|
+
console.log(" ROI: insufficient outcome data");
|
|
2981
|
+
}
|
|
2982
|
+
if (roi.secretsIncidentCount > 0) {
|
|
2983
|
+
console.log(
|
|
2984
|
+
` \u26A0 Secrets: ${roi.secretsIncidentCount} incident${roi.secretsIncidentCount === 1 ? "" : "s"} this month`
|
|
2985
|
+
);
|
|
2986
|
+
}
|
|
2987
|
+
console.log();
|
|
2988
|
+
const edge = profile.growthEdge;
|
|
2989
|
+
if (edge) {
|
|
2990
|
+
console.log(sectionHeader("GROWTH EDGE"));
|
|
2991
|
+
const edgeScore = edge.meanScore !== null ? ` (${edge.meanScore.toFixed(1)}/10)` : "";
|
|
2992
|
+
console.log(` ${edge.archetype}${edgeScore}`);
|
|
2993
|
+
const guidance = !profile.narrativeUnavailable && profile.narrative?.growthEdgeNarrative || edge.citedRationale || null;
|
|
2994
|
+
if (guidance) {
|
|
2995
|
+
console.log(` ${guidance.trim()}`);
|
|
2996
|
+
}
|
|
2997
|
+
if (edge.suggestedPatternKey) {
|
|
2998
|
+
console.log(` Suggested practice: ${edge.suggestedPatternKey}`);
|
|
2999
|
+
}
|
|
3000
|
+
console.log();
|
|
3001
|
+
}
|
|
3002
|
+
console.log(`Full report: ${reportUrl}`);
|
|
3003
|
+
}
|
|
3004
|
+
async function profileCommand(options) {
|
|
3005
|
+
let backend = null;
|
|
3006
|
+
let backendError = null;
|
|
3007
|
+
const result = await fetchProfile();
|
|
3008
|
+
if (result.error) {
|
|
3009
|
+
backendError = result.error;
|
|
3010
|
+
} else {
|
|
3011
|
+
backend = result.data;
|
|
3012
|
+
}
|
|
3013
|
+
const reportUrl = `${getBaseUrl()}/dashboard/coding-iq/builder-profile`;
|
|
3014
|
+
if (options.json) {
|
|
3015
|
+
const output = {
|
|
3016
|
+
backend,
|
|
3017
|
+
backendError,
|
|
3018
|
+
reportUrl
|
|
3019
|
+
};
|
|
3020
|
+
console.log(JSON.stringify(output, null, 2));
|
|
3021
|
+
return;
|
|
3022
|
+
}
|
|
3023
|
+
renderHuman(backend, backendError, reportUrl);
|
|
3024
|
+
}
|
|
3025
|
+
|
|
2841
3026
|
// src/commands/status.ts
|
|
2842
3027
|
import * as fs3 from "fs";
|
|
2843
|
-
function
|
|
3028
|
+
function formatDollars2(cents) {
|
|
2844
3029
|
return `$${(cents / 100).toFixed(2)}`;
|
|
2845
3030
|
}
|
|
2846
3031
|
function formatRelativeTime(isoString) {
|
|
@@ -2864,7 +3049,7 @@ function progressBar(pct) {
|
|
|
2864
3049
|
function toolLabel(tool) {
|
|
2865
3050
|
return tool.split("-").map((w) => w.charAt(0).toUpperCase() + w.slice(1)).join(" ");
|
|
2866
3051
|
}
|
|
2867
|
-
function
|
|
3052
|
+
function pad2(s, width) {
|
|
2868
3053
|
return s.length >= width ? s : s + " ".repeat(width - s.length);
|
|
2869
3054
|
}
|
|
2870
3055
|
function collectLocalState() {
|
|
@@ -2904,13 +3089,13 @@ async function fetchBackendStatus() {
|
|
|
2904
3089
|
clearTimeout(timeout);
|
|
2905
3090
|
}
|
|
2906
3091
|
}
|
|
2907
|
-
var
|
|
2908
|
-
function
|
|
3092
|
+
var SECTION_WIDTH2 = 52;
|
|
3093
|
+
function sectionHeader2(title) {
|
|
2909
3094
|
const line = `\u2500\u2500 ${title} `;
|
|
2910
|
-
return line + "\u2500".repeat(Math.max(0,
|
|
3095
|
+
return line + "\u2500".repeat(Math.max(0, SECTION_WIDTH2 - line.length));
|
|
2911
3096
|
}
|
|
2912
|
-
function
|
|
2913
|
-
console.log(
|
|
3097
|
+
function renderHuman2(workspaces, backend, backendError) {
|
|
3098
|
+
console.log(sectionHeader2("MONITORING"));
|
|
2914
3099
|
if (workspaces.length === 0) {
|
|
2915
3100
|
console.log(
|
|
2916
3101
|
" No workspaces configured. Run `olakai monitor init` in a project directory."
|
|
@@ -2919,7 +3104,7 @@ function renderHuman(workspaces, backend, backendError) {
|
|
|
2919
3104
|
for (const ws of workspaces) {
|
|
2920
3105
|
const status = ws.configured ? "\u2713 configured" : "\u2717 config missing";
|
|
2921
3106
|
console.log(
|
|
2922
|
-
` ${
|
|
3107
|
+
` ${pad2(toolLabel(ws.tool), 14)} ${pad2(status, 16)} ${ws.workspacePath}`
|
|
2923
3108
|
);
|
|
2924
3109
|
}
|
|
2925
3110
|
}
|
|
@@ -2945,7 +3130,7 @@ function renderHuman(workspaces, backend, backendError) {
|
|
|
2945
3130
|
}
|
|
2946
3131
|
const now = /* @__PURE__ */ new Date();
|
|
2947
3132
|
const monthName = now.toLocaleString("default", { month: "long" });
|
|
2948
|
-
console.log(
|
|
3133
|
+
console.log(sectionHeader2(`PERSONAL USAGE (${monthName} MTD)`));
|
|
2949
3134
|
if (!backend.identity.found) {
|
|
2950
3135
|
console.log(
|
|
2951
3136
|
" Not yet recognized in Olakai Coding IQ \u2014 spend data will appear after your first session is processed."
|
|
@@ -2954,24 +3139,24 @@ function renderHuman(workspaces, backend, backendError) {
|
|
|
2954
3139
|
console.log(
|
|
2955
3140
|
` Sessions: ${backend.monitoring.recentSessionCount}`
|
|
2956
3141
|
);
|
|
2957
|
-
console.log(` Est. cost: ${
|
|
3142
|
+
console.log(` Est. cost: ${formatDollars2(backend.spend.mtdCents)}`);
|
|
2958
3143
|
if (backend.spend.providers.length > 1) {
|
|
2959
3144
|
for (const p of backend.spend.providers) {
|
|
2960
3145
|
console.log(
|
|
2961
|
-
` ${
|
|
3146
|
+
` ${pad2(p.provider, 10)} ${formatDollars2(p.mtdCents)}`
|
|
2962
3147
|
);
|
|
2963
3148
|
}
|
|
2964
3149
|
}
|
|
2965
3150
|
}
|
|
2966
3151
|
console.log();
|
|
2967
3152
|
if (backend.budget.found && backend.budget.monthlyLimitCents !== null) {
|
|
2968
|
-
console.log(
|
|
2969
|
-
const limitStr =
|
|
3153
|
+
console.log(sectionHeader2("BUDGET"));
|
|
3154
|
+
const limitStr = formatDollars2(backend.budget.monthlyLimitCents);
|
|
2970
3155
|
console.log(` Limit: ${limitStr}/month`);
|
|
2971
3156
|
if (backend.budget.usagePct !== null) {
|
|
2972
3157
|
const pct = backend.budget.usagePct;
|
|
2973
3158
|
const bar = progressBar(pct);
|
|
2974
|
-
const spentStr =
|
|
3159
|
+
const spentStr = formatDollars2(backend.spend.mtdCents);
|
|
2975
3160
|
console.log(
|
|
2976
3161
|
` Used: ${pct.toFixed(1)}% ${bar} (${spentStr} of ${limitStr})`
|
|
2977
3162
|
);
|
|
@@ -2979,7 +3164,7 @@ function renderHuman(workspaces, backend, backendError) {
|
|
|
2979
3164
|
if (backend.spend.forecastMonthEndCents !== null && backend.budget.forecastPct !== null) {
|
|
2980
3165
|
const confidence = backend.spend.forecastConfidence === "insufficient_data" ? "insufficient data" : backend.spend.forecastConfidence;
|
|
2981
3166
|
console.log(
|
|
2982
|
-
` Forecast: ~${
|
|
3167
|
+
` Forecast: ~${formatDollars2(backend.spend.forecastMonthEndCents)} by month-end (${confidence} confidence)`
|
|
2983
3168
|
);
|
|
2984
3169
|
}
|
|
2985
3170
|
if (backend.budget.status) {
|
|
@@ -2989,7 +3174,7 @@ function renderHuman(workspaces, backend, backendError) {
|
|
|
2989
3174
|
console.log();
|
|
2990
3175
|
}
|
|
2991
3176
|
if (backend.identity.found) {
|
|
2992
|
-
console.log(
|
|
3177
|
+
console.log(sectionHeader2("IDENTITY"));
|
|
2993
3178
|
const identityLine = backend.identity.displayName ? `${backend.identity.displayName} (${backend.identity.identityCount} ${backend.identity.identityCount === 1 ? "identity" : "identities"})` : `${backend.identity.identityCount} ${backend.identity.identityCount === 1 ? "identity" : "identities"} recognized`;
|
|
2994
3179
|
console.log(` Recognized: ${identityLine}`);
|
|
2995
3180
|
if (backend.identity.projectNames.length > 0) {
|
|
@@ -3019,7 +3204,7 @@ async function statusCommand2(options) {
|
|
|
3019
3204
|
console.log(JSON.stringify(output, null, 2));
|
|
3020
3205
|
return;
|
|
3021
3206
|
}
|
|
3022
|
-
|
|
3207
|
+
renderHuman2(workspaces, backend, backendError);
|
|
3023
3208
|
}
|
|
3024
3209
|
|
|
3025
3210
|
// src/index.ts
|
|
@@ -3075,6 +3260,9 @@ registerMonitorCommand(program);
|
|
|
3075
3260
|
program.command("status").description("Show your Olakai monitoring state and personal Coding IQ status").option("--json", "Output as JSON (for machine consumption)").option("--workspace-only", "Show local monitor state only (no backend call)").action(
|
|
3076
3261
|
(opts) => statusCommand2(opts)
|
|
3077
3262
|
);
|
|
3263
|
+
program.command("profile").description(
|
|
3264
|
+
"Show your Olakai Builder Profile \u2014 archetype, dimension scores, and personal ROI"
|
|
3265
|
+
).option("--json", "Output as JSON (for machine consumption)").action((opts) => profileCommand(opts));
|
|
3078
3266
|
registerProfilesCommand(program);
|
|
3079
3267
|
program.parse();
|
|
3080
3268
|
//# sourceMappingURL=index.js.map
|