vue-framework — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited vue-framework (Agent Skill) and scored it 91/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 1 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 1 flagged
The text {match} is the classic direct prompt-injection phrasing. Placed in a skill body that the agent reads as trusted instructions, it tries to make the agent abandon its prior rules and follow whatever comes next — a full system-prompt override.
ignore/disregard/forget … previous instructions sentence.Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Vue.js is a progressive JavaScript framework for building user interfaces with reactive data binding.
Using Vite (recommended):
# Create new project
npm create vite@latest my-app -- --template vue
# Navigate and install
cd my-app
npm install
# Development server
npm run dev
# Build for production
npm run buildComponents are reusable UI elements with template, script, and style.
<template>
<div class="counter">
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>
<script>
import { ref } from 'vue';
export default {
name: 'Counter',
setup() {
const count = ref(0);
const increment = () => {
count.value++;
};
return { count, increment };
},
};
</script>
<style scoped>
.counter {
padding: 20px;
border: 1px solid #ccc;
}
button {
margin-top: 10px;
}
</style>Modern approach using functions instead of objects:
<template>
<form @submit.prevent="handleSubmit">
<input v-model="form.email" type="email" placeholder="Email" required />
<input v-model="form.password" type="password" placeholder="Password" required />
<button type="submit" :disabled="loading">{{ loading ? 'Logging in...' : 'Login' }}</button>
</form>
</template>
<script setup>
import { ref } from 'vue';
const form = ref({
email: '',
password: '',
});
const loading = ref(false);
const handleSubmit = async () => {
loading.value = true;
try {
const response = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(form.value),
});
if (response.ok) {
console.log('Login successful');
}
} catch (error) {
console.error('Login failed', error);
} finally {
loading.value = false;
}
};
</script>Reactivity is the core feature of Vue:
import { ref, computed, watch, reactive } from 'vue';
// ref for primitives
const count = ref(0);
count.value++; // Must use .value in script
// reactive for objects
const state = reactive({
user: { name: 'John', age: 30 },
items: [],
});
// computed for derived state
const userAge = computed(() => state.user.age);
// watch for side effects
watch(
() => state.user.age,
(newAge, oldAge) => {
console.log(`Age changed from ${oldAge} to ${newAge}`);
}
);
// watchers with options
watch(
() => state.items,
(newItems) => {
console.log('Items changed', newItems);
},
{ deep: true } // Watch nested properties
);Vue templates support directives and expressions:
<template>
<!-- Interpolation -->
<h1>{{ message }}</h1>
<!-- Binding -->
<img :src="imageUrl" :alt="imageName" />
<input :value="inputValue" @input="updateInput" />
<!-- v-if / v-else -->
<div v-if="isLoggedIn">Welcome!</div>
<div v-else>Please log in</div>
<!-- v-for -->
<ul>
<li v-for="item in items" :key="item.id">{{ item.name }}</li>
</ul>
<!-- v-show (toggle display) -->
<div v-show="showDetails">Details here</div>
<!-- Event handling -->
<button @click="handleClick">Click me</button>
<input @keyup.enter="submit" />
<!-- Class binding -->
<div :class="{ active: isActive, disabled: isDisabled }">Status</div>
<!-- Style binding -->
<div :style="{ color: activeColor, fontSize: fontSize + 'px' }">Styled</div>
</template>Parent-child communication:
<!-- Parent Component -->
<template>
<ChildComponent
:title="message"
@update-title="updateMessage"
/>
</template>
<script setup>
import { ref } from 'vue';
import ChildComponent from './Child.vue';
const message = ref('Hello');
const updateMessage = (newMessage) => {
message.value = newMessage;
};
</script>
<!-- Child Component -->
<template>
<div>
<h1>{{ title }}</h1>
<button @click="emitUpdate">Change Title</button>
</div>
</template>
<script setup>
defineProps({
title: {
type: String,
required: true,
},
});
const emit = defineEmits(['update-title']);
const emitUpdate = () => {
emit('update-title', 'New Title');
};
</script>React to component stages:
import { onMounted, onUpdated, onUnmounted, onBeforeMount } from 'vue';
export default {
setup() {
onBeforeMount(() => {
console.log('Component is about to mount');
});
onMounted(() => {
console.log('Component mounted');
// Fetch data, set up timers
});
onUpdated(() => {
console.log('Component updated');
});
onUnmounted(() => {
console.log('Component unmounted');
// Clean up timers, subscriptions
});
},
};Single-page application routing:
// router.js
import { createRouter, createWebHistory } from 'vue-router';
import Home from './pages/Home.vue';
import About from './pages/About.vue';
const routes = [
{ path: '/', component: Home },
{ path: '/about', component: About },
{ path: '/user/:id', component: UserDetail },
];
const router = createRouter({
history: createWebHistory(),
routes,
});
export default router;In template:
<template>
<nav>
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
</nav>
<router-view />
</template>Global state management:
// stores/counter.js
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
export const useCounterStore = defineStore('counter', () => {
const count = ref(0);
const doubleCount = computed(() => count.value * 2);
const increment = () => count.value++;
const decrement = () => count.value--;
return { count, doubleCount, increment, decrement };
});
// In component
<script setup>
import { useCounterStore } from '@/stores/counter';
const store = useCounterStore();
</script>
<template>
<div>
<p>Count: {{ store.count }}</p>
<p>Double: {{ store.doubleCount }}</p>
<button @click="store.increment">+</button>
</div>
</template>Handle form input with validation:
<script setup>
import { ref } from 'vue';
const form = ref({
name: '',
email: '',
message: '',
});
const errors = ref({});
const validateForm = () => {
errors.value = {};
if (!form.value.name) errors.value.name = 'Name is required';
if (!form.value.email.includes('@')) errors.value.email = 'Valid email required';
if (form.value.message.length < 10) errors.value.message = 'Message too short';
return Object.keys(errors.value).length === 0;
};
const handleSubmit = () => {
if (validateForm()) {
console.log('Form submitted', form.value);
}
};
</script>
<template>
<form @submit.prevent="handleSubmit">
<div>
<input v-model="form.name" placeholder="Name" />
<span v-if="errors.name" class="error">{{ errors.name }}</span>
</div>
<div>
<input v-model="form.email" type="email" placeholder="Email" />
<span v-if="errors.email" class="error">{{ errors.email }}</span>
</div>
<div>
<textarea v-model="form.message" placeholder="Message"></textarea>
<span v-if="errors.message" class="error">{{ errors.message }}</span>
</div>
<button type="submit">Send</button>
</form>
</template>Source: Vue.js Official Documentation (https://vuejs.org)
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.