@algolia/wizard 0.62.0 → 0.64.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/main.js +371 -117
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -1697,29 +1697,153 @@ function trackWorkflowError(ctx) {
|
|
|
1697
1697
|
|
|
1698
1698
|
// src/lib/events.ts
|
|
1699
1699
|
import "zod";
|
|
1700
|
-
|
|
1700
|
+
var analyticsAppId = void 0;
|
|
1701
|
+
var analyticsAgentRunId = void 0;
|
|
1702
|
+
function setAnalyticsContext(next) {
|
|
1703
|
+
analyticsAppId = next.appId;
|
|
1704
|
+
analyticsAgentRunId = next.agentRunId;
|
|
1705
|
+
}
|
|
1706
|
+
function wizardErrorType(actionId, step, error) {
|
|
1707
|
+
if (actionId === "project-scan" || step === "project scan") {
|
|
1708
|
+
return "Scan Codebase";
|
|
1709
|
+
}
|
|
1710
|
+
if (actionId === "ingestion" || step === "Push Data" || step === "ingest records") {
|
|
1711
|
+
return "Ingest Records";
|
|
1712
|
+
}
|
|
1713
|
+
if (actionId === "search" || step === "create search ui") {
|
|
1714
|
+
if (error && error.toLowerCase().includes("verification failed")) {
|
|
1715
|
+
return "Wire Component to UI";
|
|
1716
|
+
}
|
|
1717
|
+
return "Generate UI";
|
|
1718
|
+
}
|
|
1719
|
+
return void 0;
|
|
1720
|
+
}
|
|
1721
|
+
function commonEventProperties() {
|
|
1722
|
+
const properties = {};
|
|
1723
|
+
if (analyticsAppId) properties.app_id = analyticsAppId;
|
|
1724
|
+
if (analyticsAgentRunId) properties.agent_run_id = analyticsAgentRunId;
|
|
1725
|
+
return properties;
|
|
1726
|
+
}
|
|
1727
|
+
function postAnalytics(path, body, label) {
|
|
1701
1728
|
if (isTelemetryOptedOut()) return;
|
|
1702
1729
|
const token = getAuthToken();
|
|
1703
1730
|
if (!token) return;
|
|
1704
1731
|
const userId = useWizard.getState().user?.userId;
|
|
1705
1732
|
if (!userId) return;
|
|
1706
|
-
void proxyFetch(`${PROXY_BASE_URL}
|
|
1733
|
+
void proxyFetch(`${PROXY_BASE_URL}${path}`, {
|
|
1707
1734
|
method: "POST",
|
|
1708
1735
|
headers: {
|
|
1709
1736
|
"content-type": "application/json",
|
|
1710
1737
|
authorization: `Bearer ${token}`
|
|
1711
1738
|
},
|
|
1712
|
-
body: JSON.stringify(
|
|
1739
|
+
body: JSON.stringify(body)
|
|
1713
1740
|
}).catch((err) => {
|
|
1714
|
-
logger.warn({ err, event }, "failed to send analytics event");
|
|
1741
|
+
logger.warn({ err, event: label }, "failed to send analytics event");
|
|
1715
1742
|
});
|
|
1716
1743
|
}
|
|
1744
|
+
function track(event, payload) {
|
|
1745
|
+
postAnalytics(
|
|
1746
|
+
"/events",
|
|
1747
|
+
{
|
|
1748
|
+
userId: useWizard.getState().user?.userId,
|
|
1749
|
+
event,
|
|
1750
|
+
properties: { ...payload, ...commonEventProperties() }
|
|
1751
|
+
},
|
|
1752
|
+
event
|
|
1753
|
+
);
|
|
1754
|
+
}
|
|
1755
|
+
function identify(traits) {
|
|
1756
|
+
const userId = useWizard.getState().user?.userId;
|
|
1757
|
+
postAnalytics("/identify", { userId, traits }, "identify");
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
// package.json
|
|
1761
|
+
var package_default = {
|
|
1762
|
+
name: "@algolia/wizard",
|
|
1763
|
+
version: "0.64.0",
|
|
1764
|
+
description: "Magically implement Algolia functionality in your codebase",
|
|
1765
|
+
type: "module",
|
|
1766
|
+
engines: {
|
|
1767
|
+
node: ">=24"
|
|
1768
|
+
},
|
|
1769
|
+
bin: {
|
|
1770
|
+
wizard: "dist/main.js"
|
|
1771
|
+
},
|
|
1772
|
+
files: [
|
|
1773
|
+
"dist",
|
|
1774
|
+
"docs"
|
|
1775
|
+
],
|
|
1776
|
+
scripts: {
|
|
1777
|
+
"build:proxy": "node scripts/build.mjs proxy",
|
|
1778
|
+
build: "node scripts/build.mjs",
|
|
1779
|
+
"dev:proxy": "touch .env && NODE_OPTIONS=--use-system-ca tsx watch --env-file=.env src/proxy/index.ts",
|
|
1780
|
+
dev: "touch .env && tsx --env-file=.env ./src/main.tsx",
|
|
1781
|
+
"env:load": "pnpm exec -- varlock load",
|
|
1782
|
+
prepare: "husky",
|
|
1783
|
+
prepublishOnly: "pnpm build",
|
|
1784
|
+
reset: "tsx ./scripts/reset-state.ts",
|
|
1785
|
+
"test:fixtures": "touch .env && tsx --env-file=.env ./fixtures/run-fixtures.ts",
|
|
1786
|
+
"test:tools": "tsx ./tool-evals/toolEval.ts",
|
|
1787
|
+
"test:tools:improve": "tsx ./tool-evals/improveFromPlan.ts",
|
|
1788
|
+
test: "vitest",
|
|
1789
|
+
typecheck: "tsc --noEmit -p tsconfig.json"
|
|
1790
|
+
},
|
|
1791
|
+
keywords: [],
|
|
1792
|
+
author: "",
|
|
1793
|
+
license: "ISC",
|
|
1794
|
+
packageManager: "pnpm@11.9.0+sha512.bd682d5d03fe525ef7c9fd6780c6884d1e756ac4c9c9fe00c538782824310dcf90e3ddc4f53835f06dfaebd5085e41855e0bcbb3b60de2ac5bbab89e5036f03b",
|
|
1795
|
+
devDependencies: {
|
|
1796
|
+
"@clack/prompts": "^1.6.0",
|
|
1797
|
+
"@types/ioredis-mock": "^8.2.7",
|
|
1798
|
+
"@types/node": "^25.9.1",
|
|
1799
|
+
"@types/react": "^19.2.16",
|
|
1800
|
+
esbuild: "^0.28.0",
|
|
1801
|
+
husky: "^9.1.7",
|
|
1802
|
+
"ink-testing-library": "^4.0.0",
|
|
1803
|
+
"ioredis-mock": "^8.13.1",
|
|
1804
|
+
"lint-staged": "^17.0.8",
|
|
1805
|
+
tsx: "^4.22.3",
|
|
1806
|
+
typescript: "^6.0.3",
|
|
1807
|
+
vitest: "^4.1.8"
|
|
1808
|
+
},
|
|
1809
|
+
dependencies: {
|
|
1810
|
+
"@ai-sdk/anthropic": "^3.0.81",
|
|
1811
|
+
"@ai-sdk/openai-compatible": "^2.0.47",
|
|
1812
|
+
"@hono/node-server": "^2.0.10",
|
|
1813
|
+
"@segment/analytics-node": "^3.1.0",
|
|
1814
|
+
ai: "^6.0.190",
|
|
1815
|
+
"cross-keychain": "^1.1.0",
|
|
1816
|
+
dotenv: "^17.4.2",
|
|
1817
|
+
hono: "^4.12.27",
|
|
1818
|
+
ink: "^7.0.5",
|
|
1819
|
+
"ink-picture": "^2.1.0",
|
|
1820
|
+
"ink-spinner": "^5.0.0",
|
|
1821
|
+
ioredis: "^5.11.1",
|
|
1822
|
+
nanoid: "^5.1.15",
|
|
1823
|
+
pino: "^10.3.1",
|
|
1824
|
+
react: "^19.2.7",
|
|
1825
|
+
"terminal-link": "^5.0.0",
|
|
1826
|
+
varlock: "^1.5.1",
|
|
1827
|
+
zod: "^4.4.3",
|
|
1828
|
+
zustand: "^5.0.14"
|
|
1829
|
+
}
|
|
1830
|
+
};
|
|
1717
1831
|
|
|
1718
1832
|
// src/core/orchestrator.ts
|
|
1719
1833
|
function defineStep(step) {
|
|
1720
1834
|
return { visible: true, ...step };
|
|
1721
1835
|
}
|
|
1722
1836
|
var nowIso = () => (/* @__PURE__ */ new Date()).toISOString();
|
|
1837
|
+
var ReturnToStepSignal = class extends Error {
|
|
1838
|
+
constructor(targetIndex, stepId) {
|
|
1839
|
+
super(`returnToStep: ${stepId}`);
|
|
1840
|
+
this.targetIndex = targetIndex;
|
|
1841
|
+
this.stepId = stepId;
|
|
1842
|
+
this.name = "ReturnToStepSignal";
|
|
1843
|
+
}
|
|
1844
|
+
targetIndex;
|
|
1845
|
+
stepId;
|
|
1846
|
+
};
|
|
1723
1847
|
function ensureExecutedStepCount(state) {
|
|
1724
1848
|
if (state.executedStepCount == null) {
|
|
1725
1849
|
state.executedStepCount = state.steps.filter(
|
|
@@ -1766,9 +1890,37 @@ function initWorkflowState(workflow, now, appId) {
|
|
|
1766
1890
|
status: "pending"
|
|
1767
1891
|
})),
|
|
1768
1892
|
algoliaState: appId ? { appId } : {},
|
|
1769
|
-
userInputs: {}
|
|
1893
|
+
userInputs: {},
|
|
1894
|
+
agentRunId: crypto.randomUUID()
|
|
1770
1895
|
};
|
|
1771
1896
|
}
|
|
1897
|
+
function ensureAgentRunId(state) {
|
|
1898
|
+
if (!state.agentRunId) state.agentRunId = crypto.randomUUID();
|
|
1899
|
+
}
|
|
1900
|
+
function completeEventProperties(state, totalDurationMs, stepCount) {
|
|
1901
|
+
const indexName = state.steps.find((s) => s.id === "select-index")?.output?.selection;
|
|
1902
|
+
const framework = state.steps.find((s) => s.id === "confirm-framework")?.output?.frameworks?.[0]?.name;
|
|
1903
|
+
return {
|
|
1904
|
+
total_duration_ms: totalDurationMs,
|
|
1905
|
+
duration_ms: totalDurationMs,
|
|
1906
|
+
step_count: stepCount,
|
|
1907
|
+
index_name: indexName ?? "unknown",
|
|
1908
|
+
framework: framework ?? "unknown"
|
|
1909
|
+
};
|
|
1910
|
+
}
|
|
1911
|
+
function errorCodeFrom(err) {
|
|
1912
|
+
let current = err;
|
|
1913
|
+
for (let i = 0; i < 4 && current; i++) {
|
|
1914
|
+
if (current && typeof current === "object" && "statusCode" in current) {
|
|
1915
|
+
const code = current.statusCode;
|
|
1916
|
+
if (typeof code === "number" || typeof code === "string") {
|
|
1917
|
+
return String(code);
|
|
1918
|
+
}
|
|
1919
|
+
}
|
|
1920
|
+
current = current instanceof Error ? current.cause : void 0;
|
|
1921
|
+
}
|
|
1922
|
+
return void 0;
|
|
1923
|
+
}
|
|
1772
1924
|
async function ensureConsent() {
|
|
1773
1925
|
const config = await loadConfig();
|
|
1774
1926
|
if (config.aiConsent) return;
|
|
@@ -1812,12 +1964,37 @@ async function makeContext(state) {
|
|
|
1812
1964
|
setUserInput: (key, value) => {
|
|
1813
1965
|
state.userInputs[key] = value;
|
|
1814
1966
|
},
|
|
1967
|
+
getUserInput: (key) => state.userInputs[key],
|
|
1815
1968
|
recordStepExecution: (count = 1) => {
|
|
1816
1969
|
state.executedStepCount = (state.executedStepCount ?? 0) + count;
|
|
1817
1970
|
},
|
|
1971
|
+
returnToStep: (stepId) => {
|
|
1972
|
+
const targetIndex = state.steps.findIndex((s) => s.id === stepId);
|
|
1973
|
+
if (targetIndex === -1) {
|
|
1974
|
+
throw new Error(`returnToStep: unknown step id "${stepId}"`);
|
|
1975
|
+
}
|
|
1976
|
+
if (targetIndex >= state.currentStepIndex) {
|
|
1977
|
+
throw new Error(
|
|
1978
|
+
`returnToStep: "${stepId}" is not before the running step "${state.steps[state.currentStepIndex]?.id}"`
|
|
1979
|
+
);
|
|
1980
|
+
}
|
|
1981
|
+
throw new ReturnToStepSignal(targetIndex, stepId);
|
|
1982
|
+
},
|
|
1818
1983
|
config: await loadConfig()
|
|
1819
1984
|
};
|
|
1820
1985
|
}
|
|
1986
|
+
async function rewindTo(state, targetIndex, fromIndex) {
|
|
1987
|
+
for (let i = targetIndex; i <= fromIndex; i++) {
|
|
1988
|
+
const record = state.steps[i];
|
|
1989
|
+
record.status = "pending";
|
|
1990
|
+
delete record.output;
|
|
1991
|
+
delete record.error;
|
|
1992
|
+
}
|
|
1993
|
+
state.currentStepIndex = targetIndex;
|
|
1994
|
+
state.updatedAt = nowIso();
|
|
1995
|
+
useWizard.getState().syncSteps([...state.steps], targetIndex);
|
|
1996
|
+
await saveWorkflowState(state);
|
|
1997
|
+
}
|
|
1821
1998
|
async function runStep(state, index, step, appId) {
|
|
1822
1999
|
const store = useWizard.getState();
|
|
1823
2000
|
const record = state.steps[index];
|
|
@@ -1839,9 +2016,18 @@ async function runStep(state, index, step, appId) {
|
|
|
1839
2016
|
await saveWorkflowState(state);
|
|
1840
2017
|
await markInteraction();
|
|
1841
2018
|
const ctx = await makeContext(state);
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
2019
|
+
let output;
|
|
2020
|
+
try {
|
|
2021
|
+
const raw = await step.run(ctx);
|
|
2022
|
+
output = step.outputSchema.parse(raw);
|
|
2023
|
+
await step.onStepComplete?.(output, ctx);
|
|
2024
|
+
} catch (err) {
|
|
2025
|
+
if (err instanceof ReturnToStepSignal) {
|
|
2026
|
+
await rewindTo(state, err.targetIndex, index);
|
|
2027
|
+
return err.targetIndex;
|
|
2028
|
+
}
|
|
2029
|
+
throw err;
|
|
2030
|
+
}
|
|
1845
2031
|
record.status = "done";
|
|
1846
2032
|
record.output = output;
|
|
1847
2033
|
state.updatedAt = nowIso();
|
|
@@ -1854,6 +2040,7 @@ async function runStep(state, index, step, appId) {
|
|
|
1854
2040
|
actionTitle: step.title,
|
|
1855
2041
|
durationMs: Date.now() - startedAt
|
|
1856
2042
|
});
|
|
2043
|
+
return void 0;
|
|
1857
2044
|
}
|
|
1858
2045
|
var RESUME_OPTION = "Resume";
|
|
1859
2046
|
var START_NEW_OPTION = "Start a new one";
|
|
@@ -1881,6 +2068,8 @@ async function runWorkflow(workflow, appId, options) {
|
|
|
1881
2068
|
try {
|
|
1882
2069
|
const state = await resolveWorkflowState(workflow, appId, options);
|
|
1883
2070
|
ensureExecutedStepCount(state);
|
|
2071
|
+
ensureAgentRunId(state);
|
|
2072
|
+
setAnalyticsContext({ appId, agentRunId: state.agentRunId });
|
|
1884
2073
|
store.startWorkflow(
|
|
1885
2074
|
{
|
|
1886
2075
|
id: workflow.id,
|
|
@@ -1891,8 +2080,15 @@ async function runWorkflow(workflow, appId, options) {
|
|
|
1891
2080
|
);
|
|
1892
2081
|
await ensureConsent();
|
|
1893
2082
|
trackWorkflowStart({ workflowId: workflow.id, appId });
|
|
1894
|
-
|
|
1895
|
-
|
|
2083
|
+
track("AI Wizard Started", {
|
|
2084
|
+
version: package_default.version,
|
|
2085
|
+
wizard_version: package_default.version,
|
|
2086
|
+
os: process.platform
|
|
2087
|
+
});
|
|
2088
|
+
let i = state.currentStepIndex;
|
|
2089
|
+
while (i < workflow.steps.length) {
|
|
2090
|
+
const rewoundTo = await runStep(state, i, workflow.steps[i], appId);
|
|
2091
|
+
i = rewoundTo ?? i + 1;
|
|
1896
2092
|
}
|
|
1897
2093
|
const totalDurationMs = Date.now() - Date.parse(state.startedAt);
|
|
1898
2094
|
const stepCount = state.executedStepCount ?? state.steps.filter((s) => s.status === "done" && isStepVisible(s)).length;
|
|
@@ -1902,10 +2098,11 @@ async function runWorkflow(workflow, appId, options) {
|
|
|
1902
2098
|
total_duration: Math.round(totalDurationMs / 1e3),
|
|
1903
2099
|
total_steps: stepCount
|
|
1904
2100
|
});
|
|
1905
|
-
track(
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
2101
|
+
track(
|
|
2102
|
+
"AI Wizard Completed",
|
|
2103
|
+
completeEventProperties(state, totalDurationMs, stepCount)
|
|
2104
|
+
);
|
|
2105
|
+
identify({ is_Wizard_user: true });
|
|
1909
2106
|
await recordWorkflowRun(workflow.id, nowIso());
|
|
1910
2107
|
await clearWorkflowState(workflow.id);
|
|
1911
2108
|
store.setDone();
|
|
@@ -1946,10 +2143,15 @@ async function runWorkflow(workflow, appId, options) {
|
|
|
1946
2143
|
actionId: failedActionId,
|
|
1947
2144
|
cause: err
|
|
1948
2145
|
});
|
|
2146
|
+
const errorType = wizardErrorType(failedActionId, step, message);
|
|
2147
|
+
const errorCode2 = errorCodeFrom(err);
|
|
1949
2148
|
track("Error", {
|
|
1950
2149
|
step,
|
|
1951
2150
|
error: message,
|
|
1952
|
-
|
|
2151
|
+
error_message: message,
|
|
2152
|
+
product_area: "AI Wizard",
|
|
2153
|
+
...errorType ? { error_type: errorType } : {},
|
|
2154
|
+
...errorCode2 ? { error_code: errorCode2 } : {}
|
|
1953
2155
|
});
|
|
1954
2156
|
store.setError(message);
|
|
1955
2157
|
}
|
|
@@ -3529,7 +3731,7 @@ function generateRecordTool(ctx, createModel = defaultCreateModel2) {
|
|
|
3529
3731
|
try {
|
|
3530
3732
|
const anthropic = createModel();
|
|
3531
3733
|
const value = z17.union([z17.string(), z17.number(), z17.boolean(), z17.null()]);
|
|
3532
|
-
const
|
|
3734
|
+
const recordSchema2 = z17.object(
|
|
3533
3735
|
Object.fromEntries(attributes.map((attr) => [attr, value]))
|
|
3534
3736
|
);
|
|
3535
3737
|
const generateBatch = async (batchCount) => {
|
|
@@ -3540,7 +3742,7 @@ function generateRecordTool(ctx, createModel = defaultCreateModel2) {
|
|
|
3540
3742
|
model: anthropic(RECORD_MODEL),
|
|
3541
3743
|
output: Output2.object({
|
|
3542
3744
|
schema: z17.object({
|
|
3543
|
-
records: z17.array(
|
|
3745
|
+
records: z17.array(recordSchema2).length(batchCount)
|
|
3544
3746
|
})
|
|
3545
3747
|
}),
|
|
3546
3748
|
prompt: [
|
|
@@ -3975,78 +4177,6 @@ async function runAnalysis(mode, extraInstructions = []) {
|
|
|
3975
4177
|
return Object.assign({}, ...results);
|
|
3976
4178
|
}
|
|
3977
4179
|
|
|
3978
|
-
// package.json
|
|
3979
|
-
var package_default = {
|
|
3980
|
-
name: "@algolia/wizard",
|
|
3981
|
-
version: "0.62.0",
|
|
3982
|
-
description: "Magically implement Algolia functionality in your codebase",
|
|
3983
|
-
type: "module",
|
|
3984
|
-
engines: {
|
|
3985
|
-
node: ">=24"
|
|
3986
|
-
},
|
|
3987
|
-
bin: {
|
|
3988
|
-
wizard: "dist/main.js"
|
|
3989
|
-
},
|
|
3990
|
-
files: [
|
|
3991
|
-
"dist",
|
|
3992
|
-
"docs"
|
|
3993
|
-
],
|
|
3994
|
-
scripts: {
|
|
3995
|
-
"build:proxy": "node scripts/build.mjs proxy",
|
|
3996
|
-
build: "node scripts/build.mjs",
|
|
3997
|
-
"dev:proxy": "touch .env && NODE_OPTIONS=--use-system-ca tsx watch --env-file=.env src/proxy/index.ts",
|
|
3998
|
-
dev: "touch .env && tsx --env-file=.env ./src/main.tsx",
|
|
3999
|
-
"env:load": "pnpm exec -- varlock load",
|
|
4000
|
-
prepare: "husky",
|
|
4001
|
-
prepublishOnly: "pnpm build",
|
|
4002
|
-
reset: "tsx ./scripts/reset-state.ts",
|
|
4003
|
-
"test:fixtures": "touch .env && tsx --env-file=.env ./fixtures/run-fixtures.ts",
|
|
4004
|
-
"test:tools": "tsx ./tool-evals/toolEval.ts",
|
|
4005
|
-
"test:tools:improve": "tsx ./tool-evals/improveFromPlan.ts",
|
|
4006
|
-
test: "vitest",
|
|
4007
|
-
typecheck: "tsc --noEmit -p tsconfig.json"
|
|
4008
|
-
},
|
|
4009
|
-
keywords: [],
|
|
4010
|
-
author: "",
|
|
4011
|
-
license: "ISC",
|
|
4012
|
-
packageManager: "pnpm@11.9.0+sha512.bd682d5d03fe525ef7c9fd6780c6884d1e756ac4c9c9fe00c538782824310dcf90e3ddc4f53835f06dfaebd5085e41855e0bcbb3b60de2ac5bbab89e5036f03b",
|
|
4013
|
-
devDependencies: {
|
|
4014
|
-
"@clack/prompts": "^1.6.0",
|
|
4015
|
-
"@types/ioredis-mock": "^8.2.7",
|
|
4016
|
-
"@types/node": "^25.9.1",
|
|
4017
|
-
"@types/react": "^19.2.16",
|
|
4018
|
-
esbuild: "^0.28.0",
|
|
4019
|
-
husky: "^9.1.7",
|
|
4020
|
-
"ink-testing-library": "^4.0.0",
|
|
4021
|
-
"ioredis-mock": "^8.13.1",
|
|
4022
|
-
"lint-staged": "^17.0.8",
|
|
4023
|
-
tsx: "^4.22.3",
|
|
4024
|
-
typescript: "^6.0.3",
|
|
4025
|
-
vitest: "^4.1.8"
|
|
4026
|
-
},
|
|
4027
|
-
dependencies: {
|
|
4028
|
-
"@ai-sdk/anthropic": "^3.0.81",
|
|
4029
|
-
"@ai-sdk/openai-compatible": "^2.0.47",
|
|
4030
|
-
"@hono/node-server": "^2.0.10",
|
|
4031
|
-
"@segment/analytics-node": "^3.1.0",
|
|
4032
|
-
ai: "^6.0.190",
|
|
4033
|
-
"cross-keychain": "^1.1.0",
|
|
4034
|
-
dotenv: "^17.4.2",
|
|
4035
|
-
hono: "^4.12.27",
|
|
4036
|
-
ink: "^7.0.5",
|
|
4037
|
-
"ink-picture": "^2.1.0",
|
|
4038
|
-
"ink-spinner": "^5.0.0",
|
|
4039
|
-
ioredis: "^5.11.1",
|
|
4040
|
-
nanoid: "^5.1.15",
|
|
4041
|
-
pino: "^10.3.1",
|
|
4042
|
-
react: "^19.2.7",
|
|
4043
|
-
"terminal-link": "^5.0.0",
|
|
4044
|
-
varlock: "^1.5.1",
|
|
4045
|
-
zod: "^4.4.3",
|
|
4046
|
-
zustand: "^5.0.14"
|
|
4047
|
-
}
|
|
4048
|
-
};
|
|
4049
|
-
|
|
4050
4180
|
// src/actions/projectScan.ts
|
|
4051
4181
|
import "zod";
|
|
4052
4182
|
var projectScanSchema = detectLanguageSchema.extend({
|
|
@@ -4055,16 +4185,19 @@ var projectScanSchema = detectLanguageSchema.extend({
|
|
|
4055
4185
|
verification: analyzeCodebaseSchema.shape.verification
|
|
4056
4186
|
});
|
|
4057
4187
|
async function projectScan(ctx) {
|
|
4188
|
+
const startedAt = Date.now();
|
|
4058
4189
|
const [detected, analyses] = await Promise.all([
|
|
4059
4190
|
detectLanguage(),
|
|
4060
4191
|
runAnalysis()
|
|
4061
4192
|
]);
|
|
4062
|
-
|
|
4063
|
-
wizard_version: package_default.version,
|
|
4064
|
-
os: process.platform
|
|
4065
|
-
});
|
|
4193
|
+
const entities = toEntitySummary(analyses.ingestionAnalysis ?? []);
|
|
4066
4194
|
track("AI Wizard Scan Completed", {
|
|
4067
|
-
|
|
4195
|
+
languages: detected.languages,
|
|
4196
|
+
frameworks: detected.frameworks,
|
|
4197
|
+
data_models_found: entities.map((entity) => entity.name),
|
|
4198
|
+
back_end_language_detected: detected.languages[0]?.name ?? null,
|
|
4199
|
+
front_end_framework_detected: detected.frameworks[0]?.name ?? null,
|
|
4200
|
+
duration_ms: Date.now() - startedAt
|
|
4068
4201
|
});
|
|
4069
4202
|
for (const [key, value] of Object.entries(analyses)) {
|
|
4070
4203
|
ctx.setUserInput(key, value);
|
|
@@ -4162,7 +4295,7 @@ var isSameFramework = (a, b) => {
|
|
|
4162
4295
|
};
|
|
4163
4296
|
function confirmed(name, version) {
|
|
4164
4297
|
const frameworks = [{ name, version: version ?? "unknown" }];
|
|
4165
|
-
track("AI Wizard Frontend Framework Confirmed", { frameworks });
|
|
4298
|
+
track("AI Wizard Frontend Framework Confirmed", { frameworks, framework: name });
|
|
4166
4299
|
return { frameworks };
|
|
4167
4300
|
}
|
|
4168
4301
|
async function askOtherFramework(ctx) {
|
|
@@ -4266,6 +4399,11 @@ var confirmEntitiesSchema = z26.object({
|
|
|
4266
4399
|
confirmedEntities: confirmedEntitiesFieldSchema
|
|
4267
4400
|
});
|
|
4268
4401
|
var SUGGEST_ENTITY = "Suggest a different entity\u2026";
|
|
4402
|
+
function usedDetectedBackend(detected, confirmed2) {
|
|
4403
|
+
if (!detected?.length || !confirmed2?.length) return false;
|
|
4404
|
+
const detectedNames = new Set(detected.map((entry) => entry.name.toLowerCase()));
|
|
4405
|
+
return confirmed2.every((entry) => detectedNames.has(entry.name.toLowerCase()));
|
|
4406
|
+
}
|
|
4269
4407
|
async function askEntityName(ctx, opts) {
|
|
4270
4408
|
const blankHint = opts?.blankHint ?? "cancel";
|
|
4271
4409
|
const declared = await promptUser(ctx, {
|
|
@@ -4372,8 +4510,14 @@ async function confirmEntities(ctx) {
|
|
|
4372
4510
|
throw new Error("User cancelled entity selection \u2014 analysis halted.");
|
|
4373
4511
|
}
|
|
4374
4512
|
ctx.setUserInput("confirmedEntities", confirmed2);
|
|
4375
|
-
|
|
4376
|
-
|
|
4513
|
+
const languages = ctx.getStepOutput(
|
|
4514
|
+
"confirm-language"
|
|
4515
|
+
)?.languages;
|
|
4516
|
+
const summary = toEntitySummary(confirmed2);
|
|
4517
|
+
track("AI Wizard Data Model Confirmed", {
|
|
4518
|
+
data_model: summary[0]?.name ?? "unknown",
|
|
4519
|
+
attribute_count: summary[0]?.attributes.length ?? 0,
|
|
4520
|
+
used_detected_back_end: usedDetectedBackend(scan.languages, languages)
|
|
4377
4521
|
});
|
|
4378
4522
|
return { ingestionAnalysis: entities, confirmedEntities: confirmed2 };
|
|
4379
4523
|
}
|
|
@@ -4423,7 +4567,7 @@ ${formatCompletedSteps(ctx.completedSteps)}`,
|
|
|
4423
4567
|
|
|
4424
4568
|
// src/actions/implement.ts
|
|
4425
4569
|
import z28 from "zod";
|
|
4426
|
-
import { mkdir as mkdir5 } from "node:fs/promises";
|
|
4570
|
+
import { mkdir as mkdir5, readFile as readFile8 } from "node:fs/promises";
|
|
4427
4571
|
import { join as join10, relative as relative6 } from "node:path";
|
|
4428
4572
|
|
|
4429
4573
|
// src/lib/git.ts
|
|
@@ -4812,6 +4956,50 @@ function outputTail(output) {
|
|
|
4812
4956
|
if (!trimmed) return void 0;
|
|
4813
4957
|
return trimmed.length > INGEST_OUTPUT_TAIL_CHARS ? `\u2026${trimmed.slice(-INGEST_OUTPUT_TAIL_CHARS)}` : trimmed;
|
|
4814
4958
|
}
|
|
4959
|
+
function jsTypeName(value) {
|
|
4960
|
+
if (value === null) return "null";
|
|
4961
|
+
if (Array.isArray(value)) return "array";
|
|
4962
|
+
const type = typeof value;
|
|
4963
|
+
if (type === "string" || type === "number" || type === "boolean" || type === "object") {
|
|
4964
|
+
return type;
|
|
4965
|
+
}
|
|
4966
|
+
return "unknown";
|
|
4967
|
+
}
|
|
4968
|
+
async function firstRecordIn(filePath) {
|
|
4969
|
+
try {
|
|
4970
|
+
const parsed = JSON.parse(await readFile8(filePath, "utf8"));
|
|
4971
|
+
const first = Array.isArray(parsed) ? parsed[0] : parsed;
|
|
4972
|
+
if (first && typeof first === "object" && !Array.isArray(first)) {
|
|
4973
|
+
return first;
|
|
4974
|
+
}
|
|
4975
|
+
} catch {
|
|
4976
|
+
return void 0;
|
|
4977
|
+
}
|
|
4978
|
+
return void 0;
|
|
4979
|
+
}
|
|
4980
|
+
async function ingestedRecordSample(repoRoot, entityName, uploadFilePath) {
|
|
4981
|
+
const candidates = [];
|
|
4982
|
+
if (entityName) {
|
|
4983
|
+
const slug = entityName.toLowerCase().replace(/[^a-z0-9]+/g, "-");
|
|
4984
|
+
candidates.push(join10(repoRoot, INGEST_DIR, "data", `${slug}.json`));
|
|
4985
|
+
}
|
|
4986
|
+
if (uploadFilePath?.toLowerCase().endsWith(".json")) {
|
|
4987
|
+
candidates.push(join10(repoRoot, uploadFilePath));
|
|
4988
|
+
}
|
|
4989
|
+
for (const candidate of candidates) {
|
|
4990
|
+
const sample = await firstRecordIn(candidate);
|
|
4991
|
+
if (sample) return sample;
|
|
4992
|
+
}
|
|
4993
|
+
return void 0;
|
|
4994
|
+
}
|
|
4995
|
+
function recordSchema(sample, attributes) {
|
|
4996
|
+
if (sample) {
|
|
4997
|
+
return Object.fromEntries(
|
|
4998
|
+
Object.entries(sample).map(([key, value]) => [key, jsTypeName(value)])
|
|
4999
|
+
);
|
|
5000
|
+
}
|
|
5001
|
+
return Object.fromEntries(attributes.map((key) => [key, "unknown"]));
|
|
5002
|
+
}
|
|
4815
5003
|
function ingestFailure(attempt, executions) {
|
|
4816
5004
|
if (!attempt) {
|
|
4817
5005
|
return {
|
|
@@ -5041,11 +5229,24 @@ async function implement(ctx, useCases = DEFAULT_IMPLEMENT_USE_CASES) {
|
|
|
5041
5229
|
if (ingestScriptRan) {
|
|
5042
5230
|
ingestOutcomeMessage = `\u2705 Ingestion succeeded${ingestRecordCount != null ? ` \u2014 ${ingestRecordCount} record(s) indexed.` : "."}`;
|
|
5043
5231
|
if (ingestRecordCount != null) {
|
|
5232
|
+
const data_model = confirmed2?.[0]?.name ?? "unknown";
|
|
5233
|
+
const sample = await ingestedRecordSample(
|
|
5234
|
+
repoRoot,
|
|
5235
|
+
confirmed2?.[0]?.name,
|
|
5236
|
+
uploadFilePath
|
|
5237
|
+
);
|
|
5044
5238
|
track("AI Wizard Ingest Successful", {
|
|
5045
|
-
|
|
5239
|
+
data_model,
|
|
5046
5240
|
record_count: ingestRecordCount,
|
|
5047
|
-
duration_ms: ingestDurationMs ?? 0
|
|
5241
|
+
duration_ms: ingestDurationMs ?? 0,
|
|
5242
|
+
index_name: targetIndex,
|
|
5243
|
+
record_schema: recordSchema(sample, confirmed2?.[0]?.attributes ?? [])
|
|
5048
5244
|
});
|
|
5245
|
+
} else {
|
|
5246
|
+
logger.warn(
|
|
5247
|
+
{ ingestCommand },
|
|
5248
|
+
"implement: ingestion ran but printed no record count; skipping Ingest Successful event"
|
|
5249
|
+
);
|
|
5049
5250
|
}
|
|
5050
5251
|
} else {
|
|
5051
5252
|
const { reason, detail } = ingestFailure(ingestAttempt, executions);
|
|
@@ -5069,7 +5270,10 @@ ${detail}` : ""}`
|
|
|
5069
5270
|
track("Error", {
|
|
5070
5271
|
step: "Push Data",
|
|
5071
5272
|
error: `ingestion did not complete: ${reason}`,
|
|
5072
|
-
|
|
5273
|
+
error_message: `ingestion did not complete: ${reason}`,
|
|
5274
|
+
error_type: "Ingest Records",
|
|
5275
|
+
product_area: "AI Wizard",
|
|
5276
|
+
...ingestAttempt?.exitCode != null ? { error_code: String(ingestAttempt.exitCode) } : {}
|
|
5073
5277
|
});
|
|
5074
5278
|
}
|
|
5075
5279
|
if (ingestScriptRan) {
|
|
@@ -5103,6 +5307,29 @@ ${detail}` : ""}`
|
|
|
5103
5307
|
let searchConfigFile;
|
|
5104
5308
|
if (useCases.includes("search")) {
|
|
5105
5309
|
let extraInstructions = [];
|
|
5310
|
+
const confirmedFrameworks = language.frameworks ?? [];
|
|
5311
|
+
const detectedFrameworks = scan.frameworks ?? [];
|
|
5312
|
+
const framework = confirmedFrameworks[0]?.name ?? "unknown";
|
|
5313
|
+
const used_detected_framework = confirmedFrameworks.some(
|
|
5314
|
+
(confirmedFw) => detectedFrameworks.some(
|
|
5315
|
+
(detectedFw) => isSameFramework(confirmedFw.name, detectedFw.name)
|
|
5316
|
+
)
|
|
5317
|
+
);
|
|
5318
|
+
const searchStartedAt = Date.now();
|
|
5319
|
+
const trackComponentGenerated = (mounted_successfully, attempts) => {
|
|
5320
|
+
const searchFilesChanged = [
|
|
5321
|
+
...new Set(useWizard.getState().writtenFiles)
|
|
5322
|
+
].map((file) => relative6(repoRoot, file));
|
|
5323
|
+
track("AI Wizard Frontend Component Generated", {
|
|
5324
|
+
file_paths: searchFilesChanged,
|
|
5325
|
+
framework,
|
|
5326
|
+
duration_ms: Date.now() - searchStartedAt,
|
|
5327
|
+
used_detected_framework,
|
|
5328
|
+
mounted_successfully,
|
|
5329
|
+
location_heuristic: searchLocation ?? "unknown",
|
|
5330
|
+
attempts
|
|
5331
|
+
});
|
|
5332
|
+
};
|
|
5106
5333
|
useWizard.getState().clearWrittenFiles();
|
|
5107
5334
|
for (let attempt = 1; attempt <= MAX_IMPLEMENT_VERIFICATION_ATTEMPTS; attempt++) {
|
|
5108
5335
|
if (attempt > 1) {
|
|
@@ -5127,19 +5354,12 @@ ${detail}` : ""}`
|
|
|
5127
5354
|
summaries.push(formatSummary("verification", verification.summary));
|
|
5128
5355
|
if (verification.sufficient) {
|
|
5129
5356
|
ctx.setUserInput("implementation", "success");
|
|
5130
|
-
|
|
5131
|
-
...new Set(useWizard.getState().writtenFiles)
|
|
5132
|
-
].map((file) => relative6(repoRoot, file));
|
|
5133
|
-
track("AI Wizard Frontend Component Generated", {
|
|
5134
|
-
filePaths: searchFilesChanged
|
|
5135
|
-
});
|
|
5136
|
-
track("AI Wizard Wired to UI", {
|
|
5137
|
-
location_heuristic: searchLocation ?? "unknown"
|
|
5138
|
-
});
|
|
5357
|
+
trackComponentGenerated(true, attempt);
|
|
5139
5358
|
break;
|
|
5140
5359
|
}
|
|
5141
5360
|
if (attempt === MAX_IMPLEMENT_VERIFICATION_ATTEMPTS) {
|
|
5142
5361
|
ctx.setUserInput("implementation", "fail");
|
|
5362
|
+
trackComponentGenerated(false, attempt);
|
|
5143
5363
|
throw new Error(
|
|
5144
5364
|
`Implementation verification failed after ${MAX_IMPLEMENT_VERIFICATION_ATTEMPTS} attempts: ${verification.additionalInstructions ?? verification.summary}`
|
|
5145
5365
|
);
|
|
@@ -5356,10 +5576,11 @@ async function selectPlaybookStep(ctx, requestedSlug) {
|
|
|
5356
5576
|
if (slugs.length === 0) {
|
|
5357
5577
|
throw new Error("No playbooks are available.");
|
|
5358
5578
|
}
|
|
5359
|
-
|
|
5579
|
+
const alreadyChose = typeof ctx.getUserInput("playbookSlug") === "string";
|
|
5580
|
+
if (!alreadyChose && requestedSlug && slugs.includes(requestedSlug)) {
|
|
5360
5581
|
return persistSlug(ctx, requestedSlug);
|
|
5361
5582
|
}
|
|
5362
|
-
const messages = requestedSlug ? [
|
|
5583
|
+
const messages = !alreadyChose && requestedSlug ? [
|
|
5363
5584
|
`"${requestedSlug}" is not a valid playbook. Choose one of the available playbooks:`
|
|
5364
5585
|
] : ["Choose a playbook:"];
|
|
5365
5586
|
const selection = await ctx.requestUserInput({
|
|
@@ -5374,6 +5595,28 @@ async function selectPlaybookStep(ctx, requestedSlug) {
|
|
|
5374
5595
|
return persistSlug(ctx, selection);
|
|
5375
5596
|
}
|
|
5376
5597
|
|
|
5598
|
+
// src/actions/playbookSteps/confirmPlaybook.ts
|
|
5599
|
+
import { z as z33 } from "zod";
|
|
5600
|
+
var confirmPlaybookSchema = z33.void();
|
|
5601
|
+
var CONTINUE_OPTION = "Looks good, continue";
|
|
5602
|
+
var GO_BACK_OPTION = "Go back";
|
|
5603
|
+
async function confirmPlaybookStep(ctx) {
|
|
5604
|
+
const { slug } = ctx.getStepOutput("select-playbook");
|
|
5605
|
+
const selection = await ctx.requestUserInput({
|
|
5606
|
+
prompt: "Ready to continue?",
|
|
5607
|
+
promptType: "multipleChoice",
|
|
5608
|
+
options: [CONTINUE_OPTION, GO_BACK_OPTION],
|
|
5609
|
+
messages: [`Playbook: ${slug}`],
|
|
5610
|
+
helpText: "Going back re-opens the playbook catalogue."
|
|
5611
|
+
});
|
|
5612
|
+
if (typeof selection !== "string") {
|
|
5613
|
+
throw new Error("confirm-playbook received an unexpected result");
|
|
5614
|
+
}
|
|
5615
|
+
if (selection === GO_BACK_OPTION) {
|
|
5616
|
+
return ctx.returnToStep("select-playbook");
|
|
5617
|
+
}
|
|
5618
|
+
}
|
|
5619
|
+
|
|
5377
5620
|
// src/lib/cli.ts
|
|
5378
5621
|
var USAGE = `Usage: wizard [workflow-id] [options]
|
|
5379
5622
|
wizard playbook [playbook-slug] [options]
|
|
@@ -5440,6 +5683,13 @@ var playbookWorkflow = {
|
|
|
5440
5683
|
title: "Select playbook",
|
|
5441
5684
|
outputSchema: selectPlaybookSchema,
|
|
5442
5685
|
run: (ctx) => selectPlaybookStep(ctx, getPlaybookSlugArg())
|
|
5686
|
+
}),
|
|
5687
|
+
defineStep({
|
|
5688
|
+
id: "confirm-playbook",
|
|
5689
|
+
title: "Confirm selections",
|
|
5690
|
+
outputSchema: confirmPlaybookSchema,
|
|
5691
|
+
visible: false,
|
|
5692
|
+
run: (ctx) => confirmPlaybookStep(ctx)
|
|
5443
5693
|
})
|
|
5444
5694
|
]
|
|
5445
5695
|
};
|
|
@@ -6459,7 +6709,7 @@ function App() {
|
|
|
6459
6709
|
}
|
|
6460
6710
|
|
|
6461
6711
|
// src/lib/envAppId.ts
|
|
6462
|
-
import { readFile as
|
|
6712
|
+
import { readFile as readFile9 } from "node:fs/promises";
|
|
6463
6713
|
import { join as join12 } from "node:path";
|
|
6464
6714
|
var ENV_FILES = [".env", ".env.local"];
|
|
6465
6715
|
var APP_ID_LINE = /^[ \t]*(?:export[ \t]+)?([A-Z0-9_]*ALGOLIA_APP(?:LICATION)?_ID)[ \t]*=[ \t]*(.*)$/gm;
|
|
@@ -6467,7 +6717,7 @@ async function findEnvApplicationId(root = process.cwd()) {
|
|
|
6467
6717
|
for (const file of ENV_FILES) {
|
|
6468
6718
|
let content;
|
|
6469
6719
|
try {
|
|
6470
|
-
content = await
|
|
6720
|
+
content = await readFile9(join12(root, file), "utf8");
|
|
6471
6721
|
} catch (err) {
|
|
6472
6722
|
if (err.code !== "ENOENT") {
|
|
6473
6723
|
logger.warn(
|
|
@@ -6654,9 +6904,13 @@ var SEEDS = {
|
|
|
6654
6904
|
review
|
|
6655
6905
|
},
|
|
6656
6906
|
playbook: {
|
|
6657
|
-
"select-playbook": selectPlaybook
|
|
6907
|
+
"select-playbook": selectPlaybook,
|
|
6908
|
+
"confirm-playbook": void 0
|
|
6658
6909
|
}
|
|
6659
6910
|
};
|
|
6911
|
+
var SEED_ALGOLIA_STATE = {
|
|
6912
|
+
playbook: { appId: "SEEDAPPID" }
|
|
6913
|
+
};
|
|
6660
6914
|
var SEED_USER_INPUTS = {
|
|
6661
6915
|
default: {
|
|
6662
6916
|
index: selectIndex.selection,
|
|
@@ -6708,7 +6962,7 @@ function buildSeedState(workflow, startIndex) {
|
|
|
6708
6962
|
updatedAt: now,
|
|
6709
6963
|
currentStepIndex: startIndex,
|
|
6710
6964
|
steps,
|
|
6711
|
-
algoliaState: {},
|
|
6965
|
+
algoliaState: startIndex > 0 ? { ...SEED_ALGOLIA_STATE[workflow.id] } : {},
|
|
6712
6966
|
userInputs: startIndex > 0 ? { ...SEED_USER_INPUTS[workflow.id] } : {}
|
|
6713
6967
|
};
|
|
6714
6968
|
}
|
|
@@ -6820,7 +7074,7 @@ function delay(ms) {
|
|
|
6820
7074
|
// package.json with { type: 'json' }
|
|
6821
7075
|
var package_default2 = {
|
|
6822
7076
|
name: "@algolia/wizard",
|
|
6823
|
-
version: "0.
|
|
7077
|
+
version: "0.64.0",
|
|
6824
7078
|
description: "Magically implement Algolia functionality in your codebase",
|
|
6825
7079
|
type: "module",
|
|
6826
7080
|
engines: {
|