@shiplens/cli 1.4.3 → 1.4.5
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/docs/02_CLI_COMMAND_REFERENCE.md +10 -1
- package/lib/assets/actions.json +769 -0
- package/lib/assets/skill.js +28 -29
- package/lib/cli.js +6 -1
- package/lib/commands/action.js +112 -0
- package/lib/commands/init.js +54 -55
- package/lib/injector.js +1 -1
- package/package.json +5 -2
- package/prompts/README.md +2 -3
- package/prompts/{prompts_cli_en.md → prompts_cli_en-US.md} +848 -743
- package/prompts/prompts_cli_zh.md +0 -743
package/lib/assets/skill.js
CHANGED
|
@@ -3,7 +3,7 @@ name: shiplens-analytics
|
|
|
3
3
|
description: Shiplens Web Analytics — Agent behavior protocol, diagnostics, and data analysis execution.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# Shiplens Web Analytics Skill (v3.
|
|
6
|
+
# Shiplens Web Analytics Skill (v3.1)
|
|
7
7
|
|
|
8
8
|
Shiplens provides web user behavior analytics via CLI and MCP. This document defines how an AI Agent should diagnose, onboard, and analyze data for any project using Shiplens.
|
|
9
9
|
|
|
@@ -86,43 +86,42 @@ Account status values:
|
|
|
86
86
|
|
|
87
87
|
## 3. Data Analysis Protocol (6 Steps)
|
|
88
88
|
|
|
89
|
-
When
|
|
89
|
+
When processing any analytics or telemetry request:
|
|
90
90
|
|
|
91
|
-
**Step 1 —
|
|
91
|
+
**Step 1 — Read Learnings**: Check \`.shiplens/learnings.md\` for project overrides (date range, metrics, cohort intervals).
|
|
92
92
|
|
|
93
|
-
**Step 2 —
|
|
93
|
+
**Step 2 — Read Context**: Read \`.shiplens/contexts/<app_id>.md\` (or run \`shiplens context show --json\`) to ground numbers in real page routes and button labels.
|
|
94
94
|
|
|
95
|
-
**Step 3 —
|
|
95
|
+
**Step 3 — Route Execution Path (Tri-Route Decision)**:
|
|
96
|
+
- **Route A (Exact Action ID)**: If input contains an \`action_id\` (e.g. \`lifecycle_stage\` or \`Action: <id>\`), run \`shiplens action <id> --json\` to retrieve prescribed steps and commands.
|
|
97
|
+
- **Route B (Scenario Preset Match)**: If input is natural language matching one of the 42 textbook growth/retention scenarios, run \`shiplens action <id> --json\` for that scenario.
|
|
98
|
+
- **Route C (Ad-Hoc Autonomous Composition)**: If input is a custom, open-ended question without a preset action, autonomously select and compose CLI commands from the Atomic Toolset (§4) to query required metrics.
|
|
96
99
|
|
|
97
|
-
**Step 4 — Execute**: Run
|
|
100
|
+
**Step 4 — Execute**: Run selected CLI commands with Step 1 overrides applied. Always include \`--json\`.
|
|
98
101
|
|
|
99
|
-
**Step 5 — Synthesize**: Translate numbers into
|
|
102
|
+
**Step 5 — Synthesize**: Translate numbers into concrete business conclusions, metric benchmarks, and actionable next steps using UI terminology from Step 2.
|
|
100
103
|
|
|
101
|
-
**Step 6 —
|
|
102
|
-
|
|
103
|
-
### Priority
|
|
104
|
-
- **Priority 1**: \`.shiplens/learnings.md\` — user's project-specific overrides
|
|
105
|
-
- **Priority 2**: \`prompts/prompts_cli_*.md\` — 42 textbook analysis scenarios
|
|
104
|
+
**Step 6 — Record**: If user clarifies or corrects preferences (e.g., "always use 14d for cohort retention"), ask to persist to \`.shiplens/learnings.md\` (§6).
|
|
106
105
|
|
|
107
106
|
---
|
|
108
107
|
|
|
109
|
-
## 4. CLI
|
|
110
|
-
|
|
111
|
-
| Command |
|
|
112
|
-
|
|
113
|
-
| \`shiplens
|
|
114
|
-
| \`shiplens
|
|
115
|
-
| \`shiplens
|
|
116
|
-
| \`shiplens
|
|
117
|
-
| \`shiplens
|
|
118
|
-
| \`shiplens
|
|
119
|
-
| \`shiplens
|
|
120
|
-
| \`shiplens
|
|
121
|
-
| \`shiplens
|
|
122
|
-
| \`shiplens context show --json\` |
|
|
123
|
-
| \`shiplens auth bind --email <email> --json\` | Send Magic Link for
|
|
124
|
-
| \`shiplens mcp serve\` | Start local stdio MCP proxy for IDE/Agent |
|
|
125
|
-
| \`shiplens projects delete --app-id <id> --json\` | Delete project (**requires confirmation**, §5) |
|
|
108
|
+
## 4. Atomic CLI Toolset & Composition Matrix
|
|
109
|
+
|
|
110
|
+
| Command | Capability | Typical Scenarios & Composition |
|
|
111
|
+
|---------|------------|---------------------------------|
|
|
112
|
+
| \`shiplens summary --range 7d --json\` | Macro Overview | Total UV, PV, bounce rates, top geos, device distribution |
|
|
113
|
+
| \`shiplens query --metric <m> --range 7d --json\` | Multidimensional Metrics | Retention matrix (\`daily_retention\`), funnels (\`conversion_funnel\`), pageview trends |
|
|
114
|
+
| \`shiplens pages --range 7d --json\` | Page Performance | Route visit counts, average dwell time, high-traffic pages |
|
|
115
|
+
| \`shiplens paths --range 7d --json\` | User Journeys | Entry-to-exit flow, drop-off routes, navigation transitions |
|
|
116
|
+
| \`shiplens heatmap --template <id> --json\` | UI & Click Patterns | Button click distributions, wireframe skeleton click rates |
|
|
117
|
+
| \`shiplens sql --query "<sql>" --json\` | Custom Slicing | Multi-filter joins, power user segmentation, ad-hoc event queries |
|
|
118
|
+
| \`shiplens dashboards create --title "..." --prompt "..." --json\` | Dashboard Creation | AI-generated 12-column live dashboards |
|
|
119
|
+
| \`shiplens action [id] [--list] --json\` | Action Presets | 42 textbook scenario steps, commands, and theory |
|
|
120
|
+
| \`shiplens doctor --json\` | Diagnostics | Diagnose config, SDK, network, credentials |
|
|
121
|
+
| \`shiplens context show --json\` | Business Context | Inspect mapped page routes and UI button semantics |
|
|
122
|
+
| \`shiplens auth bind --email <email> --json\` | Activation | Send Magic Link email for project binding |
|
|
123
|
+
| \`shiplens mcp serve\` | MCP Server | Start local stdio MCP proxy for IDE/Agent |
|
|
124
|
+
| \`shiplens projects delete --app-id <id> --json\` | Deletion | Delete project (**requires confirmation**, §5) |
|
|
126
125
|
|
|
127
126
|
---
|
|
128
127
|
|
package/lib/cli.js
CHANGED
|
@@ -14,8 +14,9 @@ const { handleDashboards } = require('./commands/dashboards');
|
|
|
14
14
|
const { handleDoctor } = require('./commands/doctor');
|
|
15
15
|
const { handleContext } = require('./commands/context');
|
|
16
16
|
const { handleMcp } = require('./commands/mcp');
|
|
17
|
+
const { handleAction } = require('./commands/action');
|
|
17
18
|
|
|
18
|
-
let VERSION = '1.
|
|
19
|
+
let VERSION = '1.4.4';
|
|
19
20
|
try {
|
|
20
21
|
const pkg = require('../package.json');
|
|
21
22
|
if (pkg.version) VERSION = pkg.version;
|
|
@@ -90,6 +91,7 @@ Core Commands:
|
|
|
90
91
|
dashboards AI dashboard management and one-click creation (list, create [--ai])
|
|
91
92
|
doctor Run full end-to-end diagnostics on SDK, credentials, and network
|
|
92
93
|
context Manage business context dictionary (push, pull, show)
|
|
94
|
+
action Retrieve deterministic steps, commands, and theory for analysis actions (list, <action_id>)
|
|
93
95
|
mcp serve Run local MCP proxy server with device credentials
|
|
94
96
|
|
|
95
97
|
auth Subcommands:
|
|
@@ -244,6 +246,9 @@ async function runCLI(argv = process.argv.slice(2)) {
|
|
|
244
246
|
case 'context':
|
|
245
247
|
await handleContext(subcommand || 'show', args.slice(2), flags, ctx);
|
|
246
248
|
break;
|
|
249
|
+
case 'action':
|
|
250
|
+
await handleAction(cmdArgs, flags, ctx);
|
|
251
|
+
break;
|
|
247
252
|
case 'mcp':
|
|
248
253
|
await handleMcp(subcommand || 'serve');
|
|
249
254
|
break;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
|
|
4
|
+
let actionsCache = null;
|
|
5
|
+
|
|
6
|
+
function loadActions() {
|
|
7
|
+
if (actionsCache) return actionsCache;
|
|
8
|
+
const filePath = path.join(__dirname, '..', 'assets', 'actions.json');
|
|
9
|
+
try {
|
|
10
|
+
if (fs.existsSync(filePath)) {
|
|
11
|
+
const data = JSON.parse(fs.readFileSync(filePath, 'utf8'));
|
|
12
|
+
actionsCache = data.actions || [];
|
|
13
|
+
} else {
|
|
14
|
+
actionsCache = [];
|
|
15
|
+
}
|
|
16
|
+
} catch (e) {
|
|
17
|
+
actionsCache = [];
|
|
18
|
+
}
|
|
19
|
+
return actionsCache;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function findSimilarActions(id, allActions) {
|
|
23
|
+
const normalized = (id || '').toLowerCase().replace(/[-_\s]+/g, '');
|
|
24
|
+
return allActions
|
|
25
|
+
.filter((a) => {
|
|
26
|
+
const aNorm = a.id.toLowerCase().replace(/[-_\s]+/g, '');
|
|
27
|
+
return aNorm.includes(normalized) || normalized.includes(aNorm) || a.title.toLowerCase().includes(id.toLowerCase());
|
|
28
|
+
})
|
|
29
|
+
.slice(0, 3)
|
|
30
|
+
.map((a) => a.id);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
async function handleAction(cmdArgs, flags, ctx) {
|
|
34
|
+
const actions = loadActions();
|
|
35
|
+
const rawId = flags.id || (cmdArgs[0] && cmdArgs[0] !== 'list' ? cmdArgs[0] : null);
|
|
36
|
+
const isList = flags.list || cmdArgs[0] === 'list' || !rawId;
|
|
37
|
+
|
|
38
|
+
if (isList) {
|
|
39
|
+
const listData = {
|
|
40
|
+
ok: true,
|
|
41
|
+
total: actions.length,
|
|
42
|
+
actions: actions.map((a) => ({
|
|
43
|
+
id: a.id,
|
|
44
|
+
title: a.title,
|
|
45
|
+
category: a.category,
|
|
46
|
+
commands: a.commands,
|
|
47
|
+
})),
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
ctx.output(listData, () => {
|
|
51
|
+
console.log(`\n📋 Shiplens Action Preset Library (${actions.length} Scenarios)\n`);
|
|
52
|
+
const grouped = {};
|
|
53
|
+
for (const a of actions) {
|
|
54
|
+
if (!grouped[a.category]) grouped[a.category] = [];
|
|
55
|
+
grouped[a.category].push(a);
|
|
56
|
+
}
|
|
57
|
+
for (const [cat, items] of Object.entries(grouped)) {
|
|
58
|
+
console.log(` 📂 ${cat}:`);
|
|
59
|
+
for (const item of items) {
|
|
60
|
+
console.log(` • ${item.id.padEnd(28)} - ${item.title}`);
|
|
61
|
+
}
|
|
62
|
+
console.log('');
|
|
63
|
+
}
|
|
64
|
+
console.log('💡 Usage: shiplens action <action_id> [--json]');
|
|
65
|
+
});
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const targetId = rawId.toLowerCase().trim();
|
|
70
|
+
const matched = actions.find((a) => a.id.toLowerCase() === targetId);
|
|
71
|
+
|
|
72
|
+
if (!matched) {
|
|
73
|
+
const suggestions = findSimilarActions(targetId, actions);
|
|
74
|
+
const err = new Error(`Action preset '${rawId}' not found.` + (suggestions.length > 0 ? ` Did you mean: ${suggestions.join(', ')}?` : ''));
|
|
75
|
+
err.code = 'ACTION_NOT_FOUND';
|
|
76
|
+
err.suggestions = suggestions;
|
|
77
|
+
throw err;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const result = {
|
|
81
|
+
ok: true,
|
|
82
|
+
action: matched,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
ctx.output(result, () => {
|
|
86
|
+
console.log(`\n🎯 [${matched.id}] ${matched.title}`);
|
|
87
|
+
console.log(`📂 Category: ${matched.category}`);
|
|
88
|
+
if (matched.suffix) console.log(`🏷️ Suffix: ${matched.suffix}`);
|
|
89
|
+
console.log(`\n📝 Execution Steps:`);
|
|
90
|
+
for (const s of matched.steps) {
|
|
91
|
+
console.log(` ${s}`);
|
|
92
|
+
}
|
|
93
|
+
if (matched.commands && matched.commands.length > 0) {
|
|
94
|
+
console.log(`\n⚡ Prescribed CLI Commands:`);
|
|
95
|
+
for (const c of matched.commands) {
|
|
96
|
+
console.log(` $ ${c}`);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
if (matched.foundation) {
|
|
100
|
+
console.log(`\n📚 Analysis Foundation:\n ${matched.foundation}`);
|
|
101
|
+
}
|
|
102
|
+
if (matched.source) {
|
|
103
|
+
console.log(`\n📖 Source:\n ${matched.source}`);
|
|
104
|
+
}
|
|
105
|
+
console.log('');
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
module.exports = {
|
|
110
|
+
handleAction,
|
|
111
|
+
loadActions,
|
|
112
|
+
};
|
package/lib/commands/init.js
CHANGED
|
@@ -30,49 +30,29 @@ async function handleInit(args, flags, ctx) {
|
|
|
30
30
|
|
|
31
31
|
// 1. Safety check for existing project configuration
|
|
32
32
|
const existing = detectExistingApp(wd);
|
|
33
|
+
let isReusedExisting = false;
|
|
34
|
+
|
|
33
35
|
if (existing.has_existing && !flags.force) {
|
|
34
|
-
if (ctx.isJSON) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
code: 'PROJECT_EXISTS_LOCALLY',
|
|
38
|
-
message: `Existing Shiplens configuration detected (App ID: ${existing.app_id}) in ${existing.source_file}. ` +
|
|
39
|
-
`Option 1 [Recommended]: Keep existing statistics and project ID. ` +
|
|
40
|
-
`Option 2: Use --force to overwrite and request a new App ID from cloud (Note: Old dashboard stops receiving new data).`,
|
|
41
|
-
existing_app_id: existing.app_id,
|
|
42
|
-
source_file: existing.source_file,
|
|
43
|
-
project_name: existing.project_name || projectName,
|
|
44
|
-
dashboard_url: `${ctx.client.baseURL}/dashboard/${existing.app_id}`,
|
|
45
|
-
};
|
|
46
|
-
ctx.output(result);
|
|
47
|
-
process.exitCode = 1;
|
|
48
|
-
return;
|
|
49
|
-
} else if (!process.stdin.isTTY) {
|
|
50
|
-
console.log(`\n⚠️ Existing Shiplens project detected!`);
|
|
51
|
-
console.log(`📌 App ID: ${existing.app_id} (Source: ${existing.source_file})`);
|
|
52
|
-
console.log(`📊 Dashboard: ${ctx.client.baseURL}/dashboard/${existing.app_id}`);
|
|
53
|
-
console.log(`🛑 Non-interactive terminal detected (CI/Agent). Existing configuration preserved.`);
|
|
54
|
-
console.log(`💡 Option 1 [Recommended]: Keep existing setup, retain App ID and historical statistics;`);
|
|
55
|
-
console.log(`💡 Option 2: Overwrite with --force to create a new project:`);
|
|
56
|
-
console.log(` npx.cmd --yes @shiplens/cli init --force\n`);
|
|
57
|
-
return;
|
|
36
|
+
if (ctx.isJSON || !process.stdin.isTTY) {
|
|
37
|
+
// Non-interactive or JSON mode (Agent/CI): Fast-forward / Idempotent reuse of existing config
|
|
38
|
+
isReusedExisting = true;
|
|
58
39
|
} else {
|
|
59
40
|
console.log(`\n⚠️ Existing Shiplens project detected!`);
|
|
60
41
|
console.log(`📌 App ID: ${existing.app_id} (Source: ${existing.source_file})`);
|
|
61
42
|
console.log(`📊 Dashboard: ${ctx.client.baseURL}/dashboard/${existing.app_id}`);
|
|
62
|
-
console.log(`\n💡 Option 1 [Recommended]: Keep existing setup, retain App ID and historical statistics;`);
|
|
63
|
-
console.log(`💡 Option 2: Overwrite with --force to request a brand new App ID from cloud (
|
|
43
|
+
console.log(`\n💡 Option 1 [Recommended]: Keep existing setup, retain App ID and historical statistics (Press Enter or N);`);
|
|
44
|
+
console.log(`💡 Option 2: Overwrite with --force to request a brand new App ID from cloud (y):`);
|
|
64
45
|
console.log(` npx.cmd --yes @shiplens/cli init --force\n`);
|
|
65
46
|
|
|
66
47
|
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
67
48
|
const confirmed = await new Promise((resolve) => {
|
|
68
|
-
rl.question('Overwrite and create a new project? (y/N): ', (ans) => {
|
|
49
|
+
rl.question('Overwrite and create a brand new project? (y/N): ', (ans) => {
|
|
69
50
|
rl.close();
|
|
70
51
|
resolve(ans.trim().toLowerCase() === 'y' || ans.trim().toLowerCase() === 'yes');
|
|
71
52
|
});
|
|
72
53
|
});
|
|
73
54
|
if (!confirmed) {
|
|
74
|
-
|
|
75
|
-
return;
|
|
55
|
+
isReusedExisting = true;
|
|
76
56
|
}
|
|
77
57
|
}
|
|
78
58
|
}
|
|
@@ -80,40 +60,52 @@ async function handleInit(args, flags, ctx) {
|
|
|
80
60
|
// 2. Inject AI Skill (.agents/skills/shiplens/SKILL.md & Agent rules)
|
|
81
61
|
const skillFile = injectSkill(wd);
|
|
82
62
|
|
|
83
|
-
// 3. Register project on cloud
|
|
63
|
+
// 3. Register project on cloud (or reuse existing)
|
|
84
64
|
let appId = '';
|
|
85
65
|
let dashboardUrl = '';
|
|
86
66
|
let accountStatus = 'not_logged_in_unlinked';
|
|
87
67
|
let accountStatusText = 'Not Logged In (Default state after first installation or no valid local credentials)';
|
|
88
68
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
description,
|
|
93
|
-
industry,
|
|
94
|
-
genre_id: genreId,
|
|
95
|
-
subgenre_id: subgenreId,
|
|
96
|
-
feature_tags: featureTagIds.join(','),
|
|
97
|
-
platform: framework,
|
|
98
|
-
});
|
|
99
|
-
appId = connResp.app_id;
|
|
100
|
-
dashboardUrl = connResp.dashboard_url || `${ctx.client.baseURL}/dashboard/${appId}`;
|
|
101
|
-
|
|
69
|
+
if (isReusedExisting) {
|
|
70
|
+
appId = existing.app_id;
|
|
71
|
+
dashboardUrl = `${ctx.client.baseURL}/dashboard/${appId}`;
|
|
102
72
|
if (ctx.resolvedAuth && ctx.resolvedAuth.is_present) {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
accountStatusText = 'Logged In (Project linked to account)';
|
|
106
|
-
} else {
|
|
107
|
-
accountStatus = 'logged_in_unlinked';
|
|
108
|
-
accountStatusText = 'Logged In (Project not linked to account)';
|
|
109
|
-
}
|
|
73
|
+
accountStatus = 'logged_in_linked';
|
|
74
|
+
accountStatusText = 'Logged In (Project linked to account)';
|
|
110
75
|
} else {
|
|
111
76
|
accountStatus = 'not_logged_in_unlinked';
|
|
112
77
|
accountStatusText = 'Not Logged In (Default state after first installation or no valid local credentials)';
|
|
113
78
|
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
|
|
79
|
+
} else {
|
|
80
|
+
try {
|
|
81
|
+
const connResp = await ctx.client.connect({
|
|
82
|
+
project_name: projectName,
|
|
83
|
+
description,
|
|
84
|
+
industry,
|
|
85
|
+
genre_id: genreId,
|
|
86
|
+
subgenre_id: subgenreId,
|
|
87
|
+
feature_tags: featureTagIds.join(','),
|
|
88
|
+
platform: framework,
|
|
89
|
+
});
|
|
90
|
+
appId = connResp.app_id;
|
|
91
|
+
dashboardUrl = connResp.dashboard_url || `${ctx.client.baseURL}/dashboard/${appId}`;
|
|
92
|
+
|
|
93
|
+
if (ctx.resolvedAuth && ctx.resolvedAuth.is_present) {
|
|
94
|
+
if (connResp.account_linked !== false && connResp.linked !== false && !connResp.unlinked) {
|
|
95
|
+
accountStatus = 'logged_in_linked';
|
|
96
|
+
accountStatusText = 'Logged In (Project linked to account)';
|
|
97
|
+
} else {
|
|
98
|
+
accountStatus = 'logged_in_unlinked';
|
|
99
|
+
accountStatusText = 'Logged In (Project not linked to account)';
|
|
100
|
+
}
|
|
101
|
+
} else {
|
|
102
|
+
accountStatus = 'not_logged_in_unlinked';
|
|
103
|
+
accountStatusText = 'Not Logged In (Default state after first installation or no valid local credentials)';
|
|
104
|
+
}
|
|
105
|
+
} catch (netErr) {
|
|
106
|
+
netErr.code = netErr.code || 'CONNECT_FAILED';
|
|
107
|
+
throw netErr;
|
|
108
|
+
}
|
|
117
109
|
}
|
|
118
110
|
|
|
119
111
|
// 4. Inject SDK code
|
|
@@ -188,6 +180,8 @@ async function handleInit(args, flags, ctx) {
|
|
|
188
180
|
|
|
189
181
|
const result = {
|
|
190
182
|
ok: true,
|
|
183
|
+
reconnected: isReusedExisting,
|
|
184
|
+
reused_existing: isReusedExisting,
|
|
191
185
|
app_id: appId,
|
|
192
186
|
project_name: projectName,
|
|
193
187
|
description: description || undefined,
|
|
@@ -209,12 +203,17 @@ async function handleInit(args, flags, ctx) {
|
|
|
209
203
|
bound_email: targetEmail || undefined,
|
|
210
204
|
elapsed_ms: elapsed,
|
|
211
205
|
atomic_completed: true,
|
|
206
|
+
message: isReusedExisting
|
|
207
|
+
? `Existing Shiplens project detected and successfully verified (App ID: ${appId}).`
|
|
208
|
+
: `Shiplens SDK successfully integrated and project created.`,
|
|
212
209
|
};
|
|
213
210
|
|
|
214
211
|
ctx.output(result, () => {
|
|
215
212
|
console.log(`\n==================================================`);
|
|
216
|
-
console.log(
|
|
217
|
-
|
|
213
|
+
console.log(isReusedExisting
|
|
214
|
+
? `✅ Shiplens SDK verified & reconnected (${elapsed} ms)\n`
|
|
215
|
+
: `✅ Shiplens SDK successfully integrated (${elapsed} ms)\n`);
|
|
216
|
+
console.log(`📦 Project & Dashboard Information` + (isReusedExisting ? ` (Existing setup preserved)` : ''));
|
|
218
217
|
console.log(`Project Name: ${projectName}`);
|
|
219
218
|
if (description) {
|
|
220
219
|
console.log(`Description: ${description}`);
|
package/lib/injector.js
CHANGED
|
@@ -394,7 +394,7 @@ async function installSDKDependency(dir, pkgManager = 'npm') {
|
|
|
394
394
|
},
|
|
395
395
|
];
|
|
396
396
|
|
|
397
|
-
const TIER1_DELAY_MS =
|
|
397
|
+
const TIER1_DELAY_MS = 5 * 1000; // 5s (fast-forward backup mirrors on high latency)
|
|
398
398
|
const TOTAL_TIMEOUT_MS = 5 * 60 * 1000; // 5min
|
|
399
399
|
|
|
400
400
|
return new Promise((resolve) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shiplens/cli",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.5",
|
|
4
4
|
"description": "Shiplens CLI — Automated Web User Analytics & AI Agent Analysis Engine",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -28,7 +28,10 @@
|
|
|
28
28
|
},
|
|
29
29
|
"homepage": "https://shiplens.dev",
|
|
30
30
|
"scripts": {
|
|
31
|
-
"test": "node test/cli.test.js"
|
|
31
|
+
"test": "node test/cli.test.js",
|
|
32
|
+
"sync-prompts": "node scripts/sync-prompts.js",
|
|
33
|
+
"prepack": "node scripts/sync-prompts.js",
|
|
34
|
+
"prepublishOnly": "node scripts/sync-prompts.js"
|
|
32
35
|
},
|
|
33
36
|
"files": [
|
|
34
37
|
"bin",
|
package/prompts/README.md
CHANGED
|
@@ -8,9 +8,8 @@ This directory hosts the deterministic CLI scenario-based prompt libraries for S
|
|
|
8
8
|
|
|
9
9
|
```text
|
|
10
10
|
prompts/
|
|
11
|
-
├── README.md #
|
|
12
|
-
|
|
13
|
-
└── prompts_cli_zh.md # [中文] 42 个确定性 CLI 分析场景
|
|
11
|
+
├── README.md # Prompt architecture overview
|
|
12
|
+
└── prompts_cli_en-US.md # [English] 42 deterministic CLI analysis scenarios
|
|
14
13
|
```
|
|
15
14
|
|
|
16
15
|
---
|