← 返回 Skills 市场
trongnguyen29

focusnoteapp

作者 trongnguyen29 · GitHub ↗ · v1.0.0
cross-platform ✓ 安全检测通过
957
总下载
0
收藏
0
当前安装
1
版本数
在 OpenClaw 中安装
/install focusnoteapp
功能描述
Add text to today's daily note in FocusNote as a new bullet point
使用说明 (SKILL.md)

FocusNote: Add to Daily Note

This skill adds user-provided text to today's daily note in FocusNote as a new bullet point.

How It Works

  1. Reads the FocusNote documents path from ~/.lucia/documents-path.txt
  2. Generates today's date in YYYY-MM-DD format
  3. Locates or creates today's daily note
  4. Adds the user's text as a new bullet point
  5. Updates the document's JSON structure files

Prerequisites

  • FocusNote app must be running (it creates ~/.lucia/documents-path.txt on startup)
  • Node.js installed for running the helper script

Implementation

When the user asks to add text to their daily note, follow these steps:

Step 1: Read Documents Path

const fs = require("fs");
const path = require("path");
const os = require("os");

// Read the documents path from FocusNote's config file
const focusnoteConfigPath = path.join(
  os.homedir(),
  ".lucia",
  "documents-path.txt",
);
const documentsPath = fs.readFileSync(focusnoteConfigPath, "utf-8").trim();

Step 2: Generate Today's Date

const today = new Date();
const year = today.getFullYear();
const month = String(today.getMonth() + 1).padStart(2, "0");
const day = String(today.getDate()).padStart(2, "0");
const todayDocName = `${year}-${month}-${day}`;

Step 3: Locate Daily Note Folder

const dailyNotePath = path.join(documentsPath, "notes", todayDocName);
const structurePath = path.join(dailyNotePath, "_structure.json");
const metadataPath = path.join(dailyNotePath, "_metadata.json");
const nodesDir = path.join(dailyNotePath, ".nodes");

Step 4: Create Daily Note If It Doesn't Exist

if (!fs.existsSync(dailyNotePath)) {
  // Create directory structure
  fs.mkdirSync(dailyNotePath, { recursive: true });
  fs.mkdirSync(nodesDir, { recursive: true });

  // Create metadata
  const metadata = {
    name: todayDocName,
    createdAt: Date.now(),
    updatedAt: Date.now(),
  };
  fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));

  // Create empty structure
  const structure = {
    rootNodeIds: [],
    deletedNodeIds: [],
    nodes: {},
  };
  fs.writeFileSync(structurePath, JSON.stringify(structure, null, 2));
}

Step 5: Create New Bullet Node

const { v4: uuidv4 } = require("uuid"); // npm install uuid

// Generate unique node ID
const nodeId = uuidv4();
const timestamp = Date.now();

// Create Lexical bullet structure
const lexicalContent = {
  root: {
    children: [
      {
        children: [
          {
            children: [
              {
                detail: 0,
                format: 0,
                mode: "normal",
                style: "",
                text: userText, // The text from the user
                type: "text",
                version: 1,
              },
            ],
            direction: "ltr",
            format: "",
            indent: 0,
            type: "listitem",
            version: 1,
            value: 1,
          },
        ],
        direction: "ltr",
        format: "",
        indent: 0,
        type: "list",
        version: 1,
        listType: "bullet",
        start: 1,
        tag: "ul",
      },
    ],
    direction: "ltr",
    format: "",
    indent: 0,
    type: "root",
    version: 1,
  },
};

// Create node object
const newNode = {
  id: nodeId,
  content: JSON.stringify(lexicalContent),
  isFolded: false,
  isTodo: false,
  isDone: false,
  isInProgress: false,
  isBlurred: false,
  backgroundColor: null,
  createdAt: timestamp,
  updatedAt: timestamp,
};

Step 6: Save Node to Sharded Directory

// Shard by first 2 characters of node ID
const shard = nodeId.substring(0, 2);
const shardDir = path.join(nodesDir, shard);

if (!fs.existsSync(shardDir)) {
  fs.mkdirSync(shardDir, { recursive: true });
}

const nodeFilePath = path.join(shardDir, `node-${nodeId}.json`);
fs.writeFileSync(nodeFilePath, JSON.stringify(newNode, null, 2));

Step 7: Update Structure File

// Read current structure
const structure = JSON.parse(fs.readFileSync(structurePath, "utf-8"));

// Add node to structure
structure.rootNodeIds.push(nodeId);
structure.nodes[nodeId] = {
  parentId: null,
  orderIndex: structure.rootNodeIds.length - 1,
  childIds: [],
};

// Update timestamp
structure.updatedAt = timestamp;

// Save updated structure
fs.writeFileSync(structurePath, JSON.stringify(structure, null, 2));

Complete Script Example

Here's a complete Node.js script you can use:

#!/usr/bin/env node

const fs = require("fs");
const path = require("path");
const os = require("os");
const { v4: uuidv4 } = require("uuid");

function addToDailyNote(userText) {
  try {
    // Step 1: Read documents path
    const focusnoteConfigPath = path.join(
      os.homedir(),
      ".lucia",
      "documents-path.txt",
    );
    if (!fs.existsSync(focusnoteConfigPath)) {
      throw new Error(
        "FocusNote config file not found. Make sure FocusNote is running.",
      );
    }
    const documentsPath = fs.readFileSync(focusnoteConfigPath, "utf-8").trim();

    // Step 2: Generate today's date
    const today = new Date();
    const year = today.getFullYear();
    const month = String(today.getMonth() + 1).padStart(2, "0");
    const day = String(today.getDate()).padStart(2, "0");
    const todayDocName = `${year}-${month}-${day}`;

    // Step 3: Set up paths
    const dailyNotePath = path.join(documentsPath, "notes", todayDocName);
    const structurePath = path.join(dailyNotePath, "_structure.json");
    const metadataPath = path.join(dailyNotePath, "_metadata.json");
    const nodesDir = path.join(dailyNotePath, ".nodes");

    // Step 4: Create daily note if needed
    if (!fs.existsSync(dailyNotePath)) {
      fs.mkdirSync(dailyNotePath, { recursive: true });
      fs.mkdirSync(nodesDir, { recursive: true });

      const metadata = {
        name: todayDocName,
        createdAt: Date.now(),
        updatedAt: Date.now(),
      };
      fs.writeFileSync(metadataPath, JSON.stringify(metadata, null, 2));

      const structure = {
        rootNodeIds: [],
        deletedNodeIds: [],
        nodes: {},
      };
      fs.writeFileSync(structurePath, JSON.stringify(structure, null, 2));
    }

    // Step 5: Create new bullet node
    const nodeId = uuidv4();
    const timestamp = Date.now();

    const lexicalContent = {
      root: {
        children: [
          {
            children: [
              {
                children: [
                  {
                    detail: 0,
                    format: 0,
                    mode: "normal",
                    style: "",
                    text: userText,
                    type: "text",
                    version: 1,
                  },
                ],
                direction: "ltr",
                format: "",
                indent: 0,
                type: "listitem",
                version: 1,
                value: 1,
              },
            ],
            direction: "ltr",
            format: "",
            indent: 0,
            type: "list",
            version: 1,
            listType: "bullet",
            start: 1,
            tag: "ul",
          },
        ],
        direction: "ltr",
        format: "",
        indent: 0,
        type: "root",
        version: 1,
      },
    };

    const newNode = {
      id: nodeId,
      content: JSON.stringify(lexicalContent),
      isFolded: false,
      isTodo: false,
      isDone: false,
      isInProgress: false,
      isBlurred: false,
      backgroundColor: null,
      createdAt: timestamp,
      updatedAt: timestamp,
    };

    // Step 6: Save node file
    const shard = nodeId.substring(0, 2);
    const shardDir = path.join(nodesDir, shard);

    if (!fs.existsSync(shardDir)) {
      fs.mkdirSync(shardDir, { recursive: true });
    }

    const nodeFilePath = path.join(shardDir, `node-${nodeId}.json`);
    fs.writeFileSync(nodeFilePath, JSON.stringify(newNode, null, 2));

    // Step 7: Update structure
    const structure = JSON.parse(fs.readFileSync(structurePath, "utf-8"));
    structure.rootNodeIds.push(nodeId);
    structure.nodes[nodeId] = {
      parentId: null,
      orderIndex: structure.rootNodeIds.length - 1,
      childIds: [],
    };
    structure.updatedAt = timestamp;
    fs.writeFileSync(structurePath, JSON.stringify(structure, null, 2));

    console.log(`✅ Added bullet to ${todayDocName}: "${userText}"`);
    return { success: true, documentName: todayDocName, nodeId };
  } catch (error) {
    console.error("❌ Error adding to daily note:", error.message);
    return { success: false, error: error.message };
  }
}

// Example usage
if (require.main === module) {
  const userText = process.argv.slice(2).join(" ") || "New bullet point";
  addToDailyNote(userText);
}

module.exports = { addToDailyNote };

Usage Examples

User: "Add to my daily note: Finished the OpenClaw skill implementation"

Assistant: I'll add that to your daily note.

# Run the script
node add-to-daily-note.js "Finished the OpenClaw skill implementation"

Output: ✅ Added bullet to 2026-02-11: "Finished the OpenClaw skill implementation"


User: "Add a reminder to call mom tomorrow"

Assistant: I'll add that to today's note.

node add-to-daily-note.js "Reminder to call mom tomorrow"

Installation

  1. Save the script as add-to-daily-note.js in your OpenClaw skills directory
  2. Install dependencies: npm install uuid
  3. Make it executable: chmod +x add-to-daily-note.js

Notes

  • The skill creates a new bullet point each time it's called
  • Bullets are added to the end of the daily note
  • If the daily note doesn't exist, it will be created automatically
  • The FocusNote app must be running for the documents path file to exist
  • Changes are immediately visible when you open/refresh the daily note in FocusNote

Troubleshooting

Error: "FocusNote config file not found"

  • Make sure FocusNote is running
  • Check that ~/.lucia/documents-path.txt exists

Bullets not appearing in FocusNote

  • Try closing and reopening the daily note
  • Check that the node files were created in .nodes/ directory
  • Verify _structure.json was updated correctly
安全使用建议
This skill appears to do what it says: it will read ~/.lucia/documents-path.txt and then create or modify files inside your FocusNote documents folder to add a bullet point. Before installing or running it, consider: ensure Node.js is available and install the 'uuid' npm package (the skill's metadata doesn't declare this); review the script to confirm you are comfortable with it writing to your notes; back up your FocusNote data if you are concerned about accidental corruption; verify the skill source (there's no homepage or author info); and only grant it access on systems where you trust the agent to edit your local notes.
功能分析
Type: OpenClaw Skill Name: focusnoteapp Version: 1.0.0 The skill is designed to add user-provided text as a bullet point to a daily note within the FocusNote application. All file system operations (reading a config path from `~/.lucia/documents-path.txt`, creating directories, and writing JSON files) are consistent with this stated purpose. User input (`userText`) is safely embedded as a string within a JSON structure, preventing code injection. There is no evidence of data exfiltration, malicious execution, persistence mechanisms, or prompt injection attempts against the AI agent in the `SKILL.md` instructions.
能力评估
Purpose & Capability
The name/description (add text to today's FocusNote daily note) align with the actions described: reading FocusNote's documents-path, locating/creating today's note, and writing a new bullet node.
Instruction Scope
Instructions explicitly read ~/.lucia/documents-path.txt and then create/modify files under the FocusNote documents path (notes/<YYYY-MM-DD>, _structure.json, .nodes/*). Reading and writing those files is necessary for the stated task, but this means the skill will access and modify local note data — users should expect disk writes to their notes.
Install Mechanism
This is an instruction-only skill (no install spec). However the SKILL.md requires Node.js and the npm 'uuid' package; the registry metadata lists no required binaries or install steps — a metadata/instructions mismatch. The lack of an install step means the agent or user must supply Node/npm and install dependencies manually.
Credentials
No environment variables, credentials, or external service tokens are requested. The only data accessed is the FocusNote config file and files inside the user's FocusNote documents path, which is proportional to the stated purpose.
Persistence & Privilege
The skill is not force-included (always:false) and does not request elevated or cross-skill configuration. Autonomous invocation is allowed (platform default) but that is expected for a user-invokable helper.
如何使用
  1. 确保已安装 OpenClaw(本地或 Docker 部署)
  2. 在对话框中输入安装命令:/install focusnoteapp
  3. 安装完成后,直接呼叫该 Skill 的名称或使用 /focusnoteapp 触发
  4. 根据 Skill 的参数说明提供必要输入,即可获得结构化输出
版本历史
v1.0.0
FocusNote: Add to Daily Note skill, initial release. - Adds user-provided text as a new bullet point to today's daily note in FocusNote. - Automatically creates today's daily note if it doesn't exist. - Ensures notes are stored and structured in FocusNote's native directory and JSON format. - Requires Node.js and a running FocusNote app for use.
元数据
Slug focusnoteapp
版本 1.0.0
许可证
累计安装 0
当前安装数 0
历史版本数 1
常见问题

focusnoteapp 是什么?

Add text to today's daily note in FocusNote as a new bullet point. 它是一个面向 Claude Code / OpenClaw 的 AI Agent Skill 插件,目前累计下载 957 次。

如何安装 focusnoteapp?

在 OpenClaw 或 Claude Code 对话框中运行命令「/install focusnoteapp」即可一键安装,无需额外配置。

focusnoteapp 是免费的吗?

是的,focusnoteapp 完全免费(开源免费),可自由下载、安装和使用。

focusnoteapp 支持哪些平台?

focusnoteapp 跨平台运行,可在任意部署了 OpenClaw / Claude Code 的环境中使用(cross-platform)。

谁开发了 focusnoteapp?

由 trongnguyen29(@trongnguyen29)开发并维护,当前版本 v1.0.0。

💬 留言讨论