@hurshb50/setup-ubuntu 0.0.3 → 1.0.1

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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # setup-ubuntu
2
2
 
3
- Sets up a fresh Ubuntu machine with a standard set of tools, configuration, and dotfiles.
3
+ Sets up a fresh Ubuntu machine with tools, configuration, and dotfiles.
4
4
 
5
5
  ## Installation
6
6
 
@@ -10,8 +10,19 @@ curl -fsSL https://vite.plus | bash
10
10
  vpx @hurshb50/setup-ubuntu
11
11
  ```
12
12
 
13
- ## Publishing
13
+ ## After Installation
14
+
15
+ Open a new terminal, then:
14
16
 
15
- Run the `publish.yaml` workflow from the Actions tab, choosing `patch`, `minor`, or `major` for the version bump. CI checks, tests, builds, bumps the version, tags it, and stages the package on npm. It uses OIDC trusted publishing, so no npm token is needed.
17
+ - Log out and back in to use Docker without `sudo`.
18
+ - Sign in to Zed, 1Password, and Chrome.
19
+ - Run `gh auth login` to authenticate the GitHub CLI.
20
+ - Pick a wallpaper in HydraPaper.
21
+ - Put personal shell config in `~/custom.bashrc`, not `~/.bashrc`.
22
+ - Update `/.gitconfig` if you are on work machine
23
+
24
+ ## Publishing
16
25
 
17
- Nothing goes live until you approve the staged package on npmjs.com under Staged Packages. The `release.yaml` workflow creates the GitHub release once the version is live.
26
+ 1. Run `publish.yaml` from the Actions tab with a `patch`, `minor`, or `major` bump. CI checks, tests, builds, tags, and stages the package, using OIDC instead of a token.
27
+ 2. Approve the staged package on npmjs.com to publish it.
28
+ 3. `release.yaml` creates the GitHub release once the version is live.
@@ -0,0 +1,31 @@
1
+ [user]
2
+ name = Hursh Patel
3
+ email = hurshb50@gmail.com
4
+
5
+ [core]
6
+ editor = zed --wait
7
+
8
+ [init]
9
+ defaultBranch = main
10
+
11
+ [push]
12
+ autoSetupRemote = true
13
+
14
+ [merge]
15
+ conflictStyle = zdiff3
16
+
17
+ [diff]
18
+ algorithm = histogram
19
+
20
+ [fetch]
21
+ prune = true
22
+
23
+ [rerere]
24
+ enabled = true
25
+
26
+ [branch]
27
+ sort = -committerdate
28
+
29
+ [credential "https://github.com"]
30
+ helper =
31
+ helper = !/usr/bin/gh auth git-credential
@@ -1,58 +1,15 @@
1
- # Voice
2
-
3
- Default to one to three sentences. Answer, then stop. No opening praise and no
4
- closing summary of what you just wrote.
5
-
6
- Lead with the answer. The first sentence answers the question or states what
7
- changed. Detail I cannot infer comes after it, and only if it earns its place.
8
-
9
- Scale length to the task, not to your effort. One file changed gets two
10
- sentences. A tradeoff I must weigh can run a few short paragraphs. If a reply
11
- needs more than a screenful, say why in line one. Otherwise revise it shorter.
12
-
13
- Prose first. Bullets are for genuinely parallel items, not for chopping sentences
14
- into pieces.
15
-
16
- Plain words. Cut hedging, preamble, adverbs, and openers like "it is important to
17
- note". Delve, resolve, crucial, robust, seamless, leverage, showcase, testament,
18
- landscape, and underscore are banned. So is any non-technical word you would not
19
- say out loud. No em dashes, and no parentheses for asides. Sentence case headings.
20
- Bold at most one phrase per reply.
21
-
22
- Write the point once. No "not just X, but Y", no padding a list to three, and no
23
- bullet whose lead-in restates its own line.
24
-
25
- Terse means fewer sentences, not denser ones. Keep the articles and the verbs.
26
-
27
- Keep one idea per sentence, most of them under 15 words. Split anything past 20.
28
-
29
1
  # Formatting
30
2
 
31
- Blank line between every paragraph, heading, list, and code block. A paragraph
32
- break is a full blank line, not just a wrap to the next line.
33
-
34
- Never let two prose paragraphs run together, and never butt a heading against the
35
- text above it. The whitespace is part of the answer, not decoration.
3
+ - Sentences: 8 words or fewer
4
+ - Paragraphs: 2 sentences or fewer
5
+ - Sections: 3 paragraphs or fewer
6
+ - Lists: 4 words per item
7
+ - Tables: 3 columns or fewer, 3 words or fewer per cell
8
+ - Diagrams: 6 nodes, one per level
36
9
 
37
10
  # Explanation
38
11
 
39
- Show the code. Quote the lines that do the thing you are explaining, trimmed to
40
- the ones that matter. Describing what code does is not explaining it. The lines
41
- do that.
42
-
43
- Draw a diagram when the answer is a flow, a sequence, or a state machine. Keep it
44
- under ten nodes and taller than it is wide.
45
-
46
- Snippets, diagrams, and before-and-after pairs do not count against the length
47
- budget.
48
-
49
- # Delegation
50
-
51
- Do the work in this thread by default. Spawn a subagent for reads that cost more
52
- than they return: codebase search, online research, docs and changelog lookups,
53
- log and CI triage, enumerating call sites, mapping an unfamiliar repo, and
54
- summarizing a large diff.
55
-
56
- Brief it like it has no history, because it does not. "Look into the auth flow"
57
- fails; "Find where a session token is validated in src/ and return the file, the
58
- function, and whether expiry is checked" works.
12
+ - Simple
13
+ - Straightforward
14
+ - Minimal
15
+ - Avoid verbosity
@@ -6,56 +6,39 @@ disable-model-invocation: true
6
6
 
7
7
  # Design
8
8
 
9
- Turn a vague architectural idea into one API shape we agree on.
9
+ Turn a vague idea into one API shape.
10
10
 
11
- Produce the API shape, not the implementation: types, function signatures, classes with their fields and methods. No function bodies, no pseudocode, no queries. If a decision depends on how something would be built, say so in prose and let me decide.
11
+ ## Output
12
12
 
13
- ## Phase 1. Interview
14
-
15
- Interview me before designing anything.
16
-
17
- Ask me about the decisions the design has to make.
18
-
19
- Some decisions depend on others. Ask the unblocked ones now and leave the rest for a later round.
20
-
21
- When a question lands better as an example than as prose, add one: a short snippet of a caller using each option, a sketch of the types, or a diagram of the flow. Keep it small and illustrative. This is not meant to represent the final design.
22
-
23
- One option per line, each labeled, never run together in a paragraph. Assume I have not read the code you are asking about: name each option by what it does, and quote the signature, variable, or line it turns on, so I can judge it without opening the file.
24
-
25
- Put every unblocked question in one round, numbered, each with your recommended answer and whatever example it needs. Then stop and wait for mine.
13
+ - Produce the API shape
14
+ - Types, signatures, classes with fields and methods
15
+ - No implementation, no function bodies, no pseudocode
26
16
 
27
- Do not ask me for facts. Look them up, then ask me only what needs my judgement.
17
+ ## Phase 1. Interview
28
18
 
29
- Move on when the remaining questions can only be answered by trying designs. That is Phase 2.
19
+ 1. Ask only about decisions needing my judgement
20
+ 2. Move on when only trying designs can answer
30
21
 
31
22
  ## Phase 2. Ideation
32
23
 
33
- Spawn three or four subagents at once. They all solve the same problem, and each one takes a different approach.
34
-
35
- Send them different starting material. At least one starts from the code as it is today, and at least one ignores the current code and designs as if the problem were new.
24
+ - Spawn 4 subagents at once
25
+ - Send each one different starting material
36
26
 
37
27
  Each subagent returns:
38
28
 
39
- - The API shape: types, signatures, classes with fields and methods.
40
- - An example of a caller using it.
41
- - A short paragraph on what the API handles for the caller.
42
- - The rules a caller must follow, and how it fails.
43
- - What this approach makes worse.
44
-
45
- Read what comes back before Phase 3. Throw away any design that does not address the problem, and spawn a replacement with a different approach until you have three or four that do. Merge any two that describe the same shape, or re-run one with different starting material. If all of them match, either the domain forces that shape or the starting material was too alike. Tell me which you think it is.
46
-
47
- ## Phase 3. Choose together
29
+ - The API shape
30
+ - An example caller
48
31
 
49
- Present all the designs.
32
+ ## Phase 3. Feedback
50
33
 
51
- For each design, show how a caller would use it: a code snippet or a diagram, whichever fits better.
52
-
53
- Then ask me for my feedback: what I like, what I do not like, and whether to run another round of Ideation or move on to Phase 4. Do not pick a winner.
34
+ - Present all the designs
35
+ - Show how a caller would use each one
36
+ - Do not pick a winner
37
+ - Ask what I like and dislike
38
+ - Ask whether to run another round
54
39
 
55
40
  ## Phase 4. Converge
56
41
 
57
- Build one API shape from the parts I chose. It has to read as one design, not several stuck together. When two parts conflict, pick one and tell me why.
58
-
59
- Show it to me, then refine it from my feedback until I say it is done.
60
-
61
- Then output the same things the subagents returned, and explain why you chose each part. Say how much of the code we already have has to change.
42
+ - Build one API shape from my choices
43
+ - It must read as one design
44
+ - Show it, then refine from my feedback
@@ -8,28 +8,10 @@ disable-model-invocation: true
8
8
 
9
9
  Any concept, in one sitting, from the ground up.
10
10
 
11
- ## Before you start
12
-
13
- Assume I know nothing about this and have no context. Do not ask what I already know.
14
-
15
- Define every term the first time it appears, including ones that seem basic. Say what problem the concept solves and what it replaces.
16
-
17
- Do not refer to anything I have not been shown. No other files, no earlier conversations, no shared setup.
18
-
19
- Start at the beginning. Teach the first idea, then add one step at a time.
11
+ Assume no prior knowledge and no context.
20
12
 
21
13
  ## The lesson
22
14
 
23
- Each section depends on the ones before it. Use a term only after you have defined it.
24
-
25
- Concrete before abstract. Show a case that works before you name the rule that explains it.
26
-
27
- One new idea at a time. If a sentence asks me to hold two at once, split it.
28
-
29
- Grow one running example. Do not hop between unrelated ones.
30
-
31
- ## Ending
32
-
33
- Close with what this now lets me do or understand, in two sentences.
34
-
35
- Then the sources. Links to the pages you actually read, local paths for anything in this repo. Never invent a link, and if you did not read a source, say so.
15
+ - Define every term before use, even basic ones
16
+ - Each section depends on the ones before
17
+ - Open with an example, then a definition
@@ -10,7 +10,7 @@ import fs from "fs/promises";
10
10
  import { execa } from "execa";
11
11
  //#region package.json
12
12
  var name = "@hurshb50/setup-ubuntu";
13
- var version = "0.0.2";
13
+ var version = "1.0.0";
14
14
  //#endregion
15
15
  //#region source/modules/logger/logger.ts
16
16
  var Logger = class Logger {
@@ -184,6 +184,19 @@ var DependencyManager = class {
184
184
  }
185
185
  }))).every((installation) => installation === true);
186
186
  }
187
+ async authenticate() {
188
+ if (await this.isAuthenticated()) return;
189
+ process.stdout.write("Administrator access is required to install packages. You may be prompted for your password.\n");
190
+ try {
191
+ await execa("sudo", ["--validate"], {
192
+ stdin: "inherit",
193
+ stdout: "inherit",
194
+ stderr: "inherit"
195
+ });
196
+ } catch (error) {
197
+ throw new Error("Administrator access was not granted. Run 'sudo --validate' and then run this tool again.", { cause: error });
198
+ }
199
+ }
187
200
  async install(dependencies, task) {
188
201
  await this.enqueue([
189
202
  "install",
@@ -195,8 +208,17 @@ var DependencyManager = class {
195
208
  async update(task) {
196
209
  await this.enqueue(["update"], task);
197
210
  }
211
+ async isAuthenticated() {
212
+ try {
213
+ await execa("sudo", ["--non-interactive", "--validate"], { stdin: "ignore" });
214
+ return true;
215
+ } catch {
216
+ return false;
217
+ }
218
+ }
198
219
  enqueue(managerArguments, task) {
199
220
  const operation = this.queue.then(async () => {
221
+ if (!await this.isAuthenticated()) throw new Error("Administrator access is no longer available for apt-get. Run 'sudo --validate' and then run this tool again.");
200
222
  const subprocess = execa("sudo", [
201
223
  "env",
202
224
  ...["DEBIAN_FRONTEND=noninteractive", "NEEDRESTART_SUSPEND=1"],
@@ -204,13 +226,15 @@ var DependencyManager = class {
204
226
  ...managerArguments
205
227
  ], { stdin: "ignore" });
206
228
  let partial = "";
207
- subprocess.stdout?.on("data", (chunk) => {
229
+ const track = (chunk) => {
208
230
  partial += chunk.toString();
209
231
  const lines = partial.split(/\r\n|\r|\n/);
210
232
  partial = lines.pop() ?? "";
211
233
  const line = lines.at(-1)?.trim();
212
234
  if (line) task.continue(line);
213
- });
235
+ };
236
+ subprocess.stdout?.on("data", track);
237
+ subprocess.stderr?.on("data", track);
214
238
  await subprocess;
215
239
  });
216
240
  this.queue = operation.catch(() => {});
@@ -563,14 +587,16 @@ var VersionControlSystem = class {
563
587
  context.logger.add(task);
564
588
  task.start();
565
589
  const dependencies = ["git", "build-essential"];
566
- if (await context.dependencyManager.isInstalled(dependencies)) {
567
- task.finish();
568
- return;
590
+ if (!await context.dependencyManager.isInstalled(dependencies)) {
591
+ task.continue("Update package manager");
592
+ await context.dependencyManager.update(task);
593
+ task.continue(`Installing dependencies: ${dependencies.join(", ")}`);
594
+ await context.dependencyManager.install(dependencies, task);
569
595
  }
570
- task.continue("Update package manager");
571
- await context.dependencyManager.update(task);
572
- task.continue(`Installing dependencies: ${dependencies.join(", ")}`);
573
- await context.dependencyManager.install(dependencies, task);
596
+ const sourceFilePath = path.join(context.directories.assets, ".gitconfig");
597
+ const destinationFilePath = path.join(context.directories.home, ".gitconfig");
598
+ task.continue("Copy configuration");
599
+ await fs.copyFile(sourceFilePath, destinationFilePath);
574
600
  task.finish();
575
601
  }
576
602
  };
@@ -599,9 +625,10 @@ var Wallpapers = class {
599
625
  };
600
626
  //#endregion
601
627
  //#region source/setup-ubuntu.ts
602
- program.name(name).version(version).description("TODO").action(async () => {
628
+ program.name(name).version(version).description("Sets up a fresh Ubuntu machine with a standard set of tools, configuration, and dotfiles.").action(async () => {
603
629
  const logger = new Logger();
604
630
  const dependencyManager = new DependencyManager();
631
+ await dependencyManager.authenticate();
605
632
  logger.start();
606
633
  const packages = [
607
634
  new AgentRules(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hurshb50/setup-ubuntu",
3
- "version": "0.0.3",
3
+ "version": "1.0.1",
4
4
  "type": "module",
5
5
  "files": [
6
6
  "distribution"
@@ -41,7 +41,7 @@
41
41
  "onFail": "download"
42
42
  }
43
43
  },
44
- "description": "TODO",
44
+ "description": "Sets up a fresh Ubuntu machine with a standard set of tools, configuration, and dotfiles.",
45
45
  "homepage": "https://github.com/hurshb50/setup-ubuntu#readme",
46
46
  "bugs": {
47
47
  "url": "https://github.com/hurshb50/setup-ubuntu/issues"